В прошлом месяце я был в сеансе кодирования ката, играя с StingCalculator , и между итерациями и итерациями мы занимались проблемами общих хостингов. Общий хостинг дешевый, но обычно он не позволяет нам использовать какие-то функции. Например, мы не можем увидеть журнал ошибок . Это проблема, когда нам нужно посмотреть, что происходит в нашем приложении. Обычно я работаю со своими серверами, и у меня есть полный доступ к журналам ошибок. Но если мы не можем увидеть журнал ошибок и сервер настроен с отображением error = off в php.ini (типичная конфигурация на виртуальном хостинге), у нас проблема.
Мне пришло в голову одно сообщение « Мониторинг PHP-приложений в реальном времени с помощью websockets и node.js ». По сути, мы можем решить эту проблему с помощью этой техники, но если мы говорим о разделяемом хостинге без доступа к журналу ошибок, очень вероятно, что мы не сможем установить сервер node.js или даже использовать функции сокетов. Так что это не «реальное» решение нашей проблемы.
Идея состоит в том, чтобы создать вариант оригинального сценария (один из вариантов выделения сценария ). В этом scprit мы будем фиксировать ошибки и исключения и показывать их в скрипте в конце скрипта. У нас нет доступа к журналу ошибок, но мы покажем его в браузере.
Представьте себе следующий скрипт:
$a = 1/0; throw new Exception("myException"); echo "hi";
Будет показано одно предупреждение (1/0) и одно исключение (myException)
- Предупреждение: деление на ноль
- Неустранимая ошибка: необработанное исключение «Exception» с сообщением «myException»
Если мы изменим php.ini show errors = off, мы увидим красивый белый экран.
Идея в том, чтобы добавить в скрипт:
include('ErrorSniffer.php'); ErrorSniffer::factory('127.0.0.1'); $a = 1/0; throw new Exception("myException"); echo "hi";
Теперь с библиотекой ErrorSniffer мы увидим хороший вывод, даже с ошибками отображения = выкл.
Я также добавляю IP в конструктор класса, чтобы ограничить выходное сообщение одним IP. Идея состоит в том, чтобы запустить этот скрипт в производство, поэтому мы не хотим показывать сообщения об ошибках целым пользователям.
Если мы видим исходный код класса ErrorSniffer, то мы конструктор, подобный этому:
public function __construct($restingToIp) { if ($this->getip() == $restingToIp) { self::register_exceptionHandler($this); self::set_error_handler($this); self::register_shutdown_function($this); } } private static function set_error_handler(ErrorSniffer &$that) { set_error_handler(function ($errno, $errstr, $errfile, $errline) use (&$that) { $type = ErrorSniffer::getErrorName($errno); $that->registerError(array('type' => $type, 'message' => $errstr, 'file' => $errfile, 'line' => $errline)); return false; }); } private static function register_exceptionHandler(ErrorSniffer &$that) { set_exception_handler(function($exception) use (&$that) { $exceptionName = get_class($exception); $message = $exception->getMessage(); $file = $exception->getFile(); $line = $exception->getLine(); $trace = $exception->getTrace(); $that->registerError(array('type' => 'EXCEPTION', 'exception' => $exceptionName, 'message' => $message, 'file' => $file, 'line' => $line, 'trace' => $trace)); return false; }); } private static function register_shutdown_function(ErrorSniffer &$that) { register_shutdown_function(function() use (&$that) { $error = error_get_last(); if ($error['type'] == E_ERROR) { $type = ErrorSniffer::getErrorName($error['type']); $that->registerError(array('type' => $type, 'message' => $error['message'], 'file' => $error['file'], 'line' => $error['line'])); } $that->printErrors(); }); }
Как мы видим, мы будем ловить ошибки и исключения, мы заполняем переменную-член $ errors и также используем register_shutdown_function для отображения информации о завершении работы.
Вы можете увидеть полный скрипт на github здесь .
Что вы думаете?