Как регистрировать ошибки PHP в файле ошибок PHP в Zend Expressive?

Используя Zend Expressive 2.0.5, я хочу регистрировать ошибки PHP в самом файле журнала ошибок PHP, я прошел через https://docs.zendframework.com/zend-expressive/features/error-handling/#обработкаисключенийиошибок

Я также видел этот пост: Zend Expressive - отчеты об ошибках php. Что прояснило для меня многое, но все еще не решило заданный вопрос.

Что я сделал: Определил свой собственный ErrorHandlerFactory, где я прикрепил двух слушателей к Zend-stratigility's ErrorHandler

  1. First Listener использует Zend Log для входа в файл журнала моего приложения (просто подумал, что было бы неплохо иметь ошибки и в моем application.log).

  2. Во втором прослушивателе я хочу войти в файл журнала ошибок PHP, поэтому я использовал метод error_log() из php.

Вопросы:

  1. #P7# #P8#
    #P9#
    #P10#
    #P11#
    #P12#
  2. #P13# #P14# <цитата> #P15#

person Ashish Ranjan    schedule 08.02.2018    source источник


Ответы (1)


Отвечая на вопрос 1:

Я могу почти имитировать способ, которым обработчик ошибок PHP регистрирует ошибки PHP. Что я сделал:

  1. Просмотрел документы и этот ТАК вопрос. Используя их, я смог подключить слушателей к Zend-stratigility ErrorHandler.
  2. Прошелся по константам ошибок и set_error_handler(), что дало мне некоторые идеи о том, как узнать, какой тип ошибки или исключения произошел.

Ниже приведен код моего ErrorHandlerFactory, к которому я прикрепляю прослушиватели.

<?php
// TODO: PHP 7.0.8 is giving strict erros eben if this directive is not enabled. And that too, it should be enabled per file from my understanding.
//declare(strict_types = 1);
namespace App\Factories;
use Interop\Container\ContainerInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Zend\Log\Logger as ZendLogger;
use Throwable;
use Zend\Diactoros\Response;
use Zend\Expressive\Middleware\ErrorResponseGenerator;
use Zend\Stratigility\Middleware\ErrorHandler;
class ErrorHandlerFactory
{
    /**
     * @param ContainerInterface $container
     * @return ErrorHandler
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function __invoke(ContainerInterface $container)
    {
        $generator = $container->has(ErrorResponseGenerator::class)
            ? $container->get(ErrorResponseGenerator::class)
            : null;
        $errorHandler = new ErrorHandler(new Response(), $generator);

         // attaching a listener for logging into application's log file.
        if ($container->has(ZendLogger::class)) {
            /** @var ZendLogger $logger */
            $logger = $container->get(ZendLogger::class);
            $errorHandler->attachListener(function (
                Throwable $throwable,
                RequestInterface $request,
                ResponseInterface $response
            ) use ($logger) {
                $logger->err(NULL, [
                    'method'  => $request->getMethod(),
                    'uri'     => (string) $request->getUri(),
                    'message' => $throwable->getMessage(),
                    'file'    => $throwable->getFile(),
                    'line'    => $throwable->getLine(),
                ]);
            });
        }

        // Attaching second listener for logging the errors into the PHP's error log
        $errorHandler->attachListener(function (
            Throwable $throwable,
            RequestInterface $request,
            ResponseInterface $response
        ) {
            // Default Error type, when PHP Error occurs.
            $errorType = sprintf("Fatal error: Uncaught %s", get_class($throwable));
            if (get_class($throwable) === "ErrorException") {

                // this is an Exception
                /** @noinspection PhpUndefinedMethodInspection */
                $severity = $throwable->getSeverity();
                switch($severity) {
                    case E_ERROR:
                    case E_USER_ERROR:
                        $errorType = 'Fatal error';
                        break;
                    case E_USER_WARNING:
                    case E_WARNING:
                        $errorType = 'Warning';
                        break;
                    case E_USER_NOTICE:
                    case E_NOTICE:
                    case E_STRICT:
                        $errorType = 'Notice';
                        break;
                    case E_RECOVERABLE_ERROR:
                        $errorType = 'Catchable fatal error';
                        break;
                    case E_USER_DEPRECATED:
                    case E_DEPRECATED:
                        $errorType = "Deprecated";
                        break;
                    default:
                        $errorType = 'Unknown error';
                }

                error_log(sprintf("PHP %s: %s in %s on line %d", $errorType, $throwable->getMessage(), $throwable->getFile(), $throwable->getLine()), 0);
            }
            else {
                // this is an Error.
                error_log(sprintf("PHP %s: %s in %s on line %d \nStack trace:\n%s", $errorType, $throwable->getMessage(), $throwable->getFile(), $throwable->getLine(), $throwable->getTraceAsString()), 0);
            }
        });

        return $errorHandler;
    }
}

Кроме того, эту фабрику необходимо добавить в зависимости. В файле: dependencies.global.php, в массиве factories:

Заменять

Zend\Stratigility\Middleware\ErrorHandler::class => Container\ErrorHandlerFactory::class,

с участием

Zend\Stratigility\Middleware\ErrorHandler::class => \App\Factories\ErrorHandlerFactory::class

И это должно почти имитировать поведение ведения журнала, как это делает обработчик ошибок php.

Ответ на вопрос 2:

Я думаю, что это нормально, поскольку PHP сам по себе предоставляет set_error_handler(), и в любом случае мы должны сами обрабатывать ошибки, а не передавать их обработчику ошибок PHP. Если наш ErrorHandler(слушатель) может реплицировать сообщения и войти в журнал ошибок PHP, используя error_log(), тогда все в порядке.

person Ashish Ranjan    schedule 09.02.2018