В прошлом месяце я был в сеансе кодирования ката, играя с StingCalculator , и между итерациями и итерациями мы занимались проблемами общих хостингов. Общий хостинг дешевый, но обычно он не позволяет нам использовать какие-то функции. Например, мы не можем увидеть журнал ошибок . Это проблема, когда нам нужно посмотреть, что происходит в нашем приложении. Обычно я работаю со своими серверами, и у меня есть полный доступ к журналам ошибок. Но если мы не можем увидеть журнал ошибок и сервер настроен с отображением error = off в php.ini (типичная конфигурация на виртуальном хостинге), у нас проблема.
Мне пришло в голову одно сообщение « Мониторинг PHP-приложений в реальном времени с помощью websockets и node.js ». По сути, мы можем решить эту проблему с помощью этой техники, но если мы говорим о разделяемом хостинге без доступа к журналу ошибок, очень вероятно, что мы не сможем установить сервер node.js или даже использовать функции сокетов. Так что это не «реальное» решение нашей проблемы.
Идея состоит в том, чтобы создать вариант оригинального сценария (один из вариантов выделения сценария 
Представьте себе следующий скрипт:
$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 здесь .
Что вы думаете?