Current Path : /var/www/alh/system/system/library/journal3/vendor/PhpConsole/ |
Current File : /var/www/alh/system/system/library/journal3/vendor/PhpConsole/Handler.php |
<?php namespace PhpConsole; /** * Overrides PHP errors and exceptions handlers, so all errors, exceptions and debug messages will be sent to PHP Console client * By default all handled errors and exceptions will be passed to previously defined handlers * * You will need to install Google Chrome extension "PHP Console" * https://chrome.google.com/webstore/detail/php-console/nfhmhhlpfleoednkpnnnkolmclajemef * * @package PhpConsole * @version 3.1 * @link http://consle.com * @author Sergey Barbushin http://linkedin.com/in/barbushin * @copyright © Sergey Barbushin, 2011-2013. All rights reserved. * @license http://www.opensource.org/licenses/BSD-3-Clause "The BSD 3-Clause License" */ class Handler { const ERRORS_RECURSION_LIMIT = 3; /** @var Handler */ protected static $instance; /** @var Connector */ protected $connector; protected $isStarted = false; protected $isHandling = false; protected $errorsHandlerLevel; protected $handleErrors = true; protected $handleExceptions = true; protected $callOldHandlers = true; protected $oldErrorsHandler; protected $oldExceptionsHandler; protected $recursiveHandlingLevel = 0; /** * @return static */ public static function getInstance() { if(!self::$instance) { self::$instance = new static(); } return self::$instance; } protected function __construct() { $this->connector = Connector::getInstance(); } /** * @codeCoverageIgnore */ private final function __clone() { } /** * Start errors & exceptions handlers * @throws \Exception */ public function start() { if($this->isStarted) { throw new \Exception(get_called_class() . ' is already started, use ' . get_called_class() . '::getInstance()->isStarted() to check it.'); } $this->isStarted = true; if($this->handleErrors) { $this->initErrorsHandler(); } if($this->handleExceptions) { $this->initExceptionsHandler(); } } /** * Validate that method is called before start. Required for handlers configuration methods. * @throws \Exception */ protected function checkIsCalledBeforeStart() { if($this->isStarted) { throw new \Exception('This method can be called only before ' . get_class($this) . '::start()'); } } /** * Enable or disable errors handler * @param bool $isEnabled */ public function setHandleErrors($isEnabled) { $this->checkIsCalledBeforeStart(); $this->handleErrors = $isEnabled; // @codeCoverageIgnore } /** * Enable or disable exceptions handler * @param bool $isEnabled */ public function setHandleExceptions($isEnabled) { $this->checkIsCalledBeforeStart(); $this->handleExceptions = $isEnabled; // @codeCoverageIgnore } /** * Enable or disable calling overridden errors & exceptions * @param bool $isEnabled */ public function setCallOldHandlers($isEnabled) { $this->callOldHandlers = $isEnabled; } /** * @return Connector */ public function getConnector() { return $this->connector; } /** * Check if PHP Console handler is started * @return bool */ public function isStarted() { return $this->isStarted; } /** * Override PHP exceptions handler to PHP Console handler */ protected function initExceptionsHandler() { $this->oldExceptionsHandler = set_exception_handler(array($this, 'handleException')); } /** * Set custom errors handler level like E_ALL ^ E_STRICT * But, anyway, it's strongly recommended to configure ignore some errors type in PHP Console extension options * IMPORTANT: previously old error handler will be called only with new errors level * @param int $level see http://us1.php.net/manual/ru/function.error-reporting.php */ public function setErrorsHandlerLevel($level) { $this->checkIsCalledBeforeStart(); $this->errorsHandlerLevel = $level; } /** * Override PHP errors handler to PHP Console handler */ protected function initErrorsHandler() { ini_set('display_errors', false); error_reporting($this->errorsHandlerLevel ? : E_ALL | E_STRICT); $this->oldErrorsHandler = set_error_handler(array($this, 'handleError')); register_shutdown_function(array($this, 'checkFatalErrorOnShutDown')); $this->connector->registerFlushOnShutDown(); } /** * Method is called by register_shutdown_function(), it's required to handle fatal PHP errors. Never call it manually. * @codeCoverageIgnore */ public function checkFatalErrorOnShutDown() { $error = error_get_last(); if($error) { ini_set('memory_limit', memory_get_usage(true) + 1000000); // if memory limit exceeded $this->callOldHandlers = false; $this->handleError($error['type'], $error['message'], $error['file'], $error['line'], null, 1); } } /** * Handle error data * @param int|null $code * @param string|null $text * @param string|null $file * @param int|null $line * @param null $context * @param int|array $ignoreTraceCalls Ignore tracing classes by name prefix `array('PhpConsole')` or fixed number of calls to ignore */ public function handleError($code = null, $text = null, $file = null, $line = null, $context = null, $ignoreTraceCalls = 0) { if(!$this->isStarted || error_reporting() === 0 || $this->isHandlingDisabled() || ($this->errorsHandlerLevel && !($code & $this->errorsHandlerLevel))) { return; } $this->onHandlingStart(); $this->connector->getErrorsDispatcher()->dispatchError($code, $text, $file, $line, is_numeric($ignoreTraceCalls) ? $ignoreTraceCalls + 1 : $ignoreTraceCalls); if($this->oldErrorsHandler && $this->callOldHandlers) { call_user_func_array($this->oldErrorsHandler, array($code, $text, $file, $line, $context)); } $this->onHandlingComplete(); } /** * Method is called before handling any error or exception */ protected function onHandlingStart() { $this->recursiveHandlingLevel++; } /** * Method is called after handling any error or exception */ protected function onHandlingComplete() { $this->recursiveHandlingLevel--; } /** * Check if errors/exception handling is disabled * @return bool */ protected function isHandlingDisabled() { return $this->recursiveHandlingLevel >= static::ERRORS_RECURSION_LIMIT; } /** * Handle exception object * @param \Exception|\Throwable $exception */ public function handleException($exception) { if(!$this->isStarted || $this->isHandlingDisabled()) { return; } try { $this->onHandlingStart(); $this->connector->getErrorsDispatcher()->dispatchException($exception); if($this->oldExceptionsHandler && $this->callOldHandlers) { call_user_func($this->oldExceptionsHandler, $exception); } } catch(\Throwable $internalException) { $this->handleException($internalException); } catch(\Exception $internalException) { $this->handleException($internalException); } $this->onHandlingComplete(); } /** * Handle debug data * @param mixed $data * @param string|null $tags Tags separated by dot, e.g. "low.db.billing" * @param int|array $ignoreTraceCalls Ignore tracing classes by name prefix `array('PhpConsole')` or fixed number of calls to ignore */ public function debug($data, $tags = null, $ignoreTraceCalls = 0) { if($this->connector->isActiveClient()) { $this->connector->getDebugDispatcher()->dispatchDebug($data, $tags, is_numeric($ignoreTraceCalls) ? $ignoreTraceCalls + 1 : $ignoreTraceCalls); } } }