Предупреждение об устаревании не улавливается в PHP 7.4

В PHP 7.4.0 я вижу следующее предупреждение:
Deprecated: Array and string offset access syntax with curly braces is deprecated in ...
Мои обработчики ошибок/исключений не могут их перехватывать и регистрировать.

Пример:

<?php
    set_error_handler(function ($errNo, $errStr) {
        echo "set_error_handler: " . $errStr;
    });

    set_exception_handler(function ($exception) {
        echo "set_exception_handler: " . $exception->getMessage();
    });

    $b = 'test';
    $a = $b{1};

Предупреждение по-прежнему отображается в обычном выводе, и ни один из двух обработчиков не вызывается.

Я хочу регистрировать все ошибки, исключения и предупреждения в своем собственном журнале, но это предупреждение не перехватывается обработчиками. Есть ли причина для этого или решение для улавливания и регистрации всего, на что жалуется PHP (нет доступа к серверу Apache/PHP)?


person Dave    schedule 06.01.2020    source источник
comment
Возможно, потому что это обнаруживается во время синтаксического анализа, а не во время выполнения.   -  person Barmar    schedule 07.01.2020
comment
Похожий вопрос (не пометка как обман на всякий случай, так как 0 голосов + лично не пробовал подход, указанный в ответе)   -  person Jeto    schedule 07.01.2020
comment
Отвечает ли это на ваш вопрос? Синтаксис доступа к смещению массива и строки с фигурными скобками устарело   -  person Martin Zeitler    schedule 07.01.2020
comment
@Jeto: связанный ответ не работает, так как обработчик никогда не вызывается в моем случае/примере.   -  person Dave    schedule 07.01.2020
comment
@MartinZeitler: я знаю, что это устарело, но я не просил решения для предупреждения об устаревании. Я спросил о возможности отлова и протоколирования такого предупреждения. Проблема в том, что обычные способы сделать это не работают в этом случае / с этим конкретным предупреждением.   -  person Dave    schedule 07.01.2020
comment
@Barmar: Возможно, но разве нет возможности поймать такое предупреждение? Я не хочу, чтобы клиент видел это сообщение, и я хочу, чтобы оно было в моем журнале ошибок. У меня нет доступа к журналу на сервере, поэтому я ловлю все ошибки и предупреждения непосредственно в PHP и записываю их в свой собственный файл журнала.   -  person Dave    schedule 07.01.2020
comment
@Dave Вы, должно быть, пропустили часть, где он использует include для включения файла, вызывающего предупреждение, после установки обработчика ошибок в родительском скрипте. Кажется, что это работает (проверено локально), но непоследовательно (не запускает обработчик ошибок при последующих выполнениях, как если бы PHP хранил локальный кеш или что-то в этом роде - отредактируйте: да) и в любом случае своего рода уловка. Не уверен, что с этим можно что-то еще сделать.   -  person Jeto    schedule 07.01.2020
comment
@Jeto: не имеет значения. Если я создам два обработчика в одном файле, а затем включу другой файл, содержащий $b = 'test'; $a = $b{1};, предупреждение останется прежним. Единственная разница заключается в файле и строке находки.   -  person Dave    schedule 07.01.2020
comment
@Dave Что ж, это должно работать, если PHP еще не имеет включенного файла в кеше. В любом случае это работает для меня (по крайней мере, из CLI, у меня нет веб-сервера, совместимого с PHP 7.4). В любом случае, это не последовательное решение, как упоминалось выше.   -  person Jeto    schedule 07.01.2020
comment
Существует множество ошибок, которые нельзя отловить с помощью set_error_handler(): Следующие типы ошибок не могут быть обработаны пользовательской функцией: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING и большая часть E_STRICT, возникших в файле. где вызывается set_error_handler(). Таким образом, вы не должны полагаться на него как на способ сокрытия ошибок от пользователей.   -  person Barmar    schedule 07.01.2020
comment
Вместо этого вы должны настроить ошибки так, чтобы они записывались в файл журнала, а не выводились пользователю.   -  person Barmar    schedule 07.01.2020


Ответы (1)


set_error_handler перехватывает сообщения, отправленные во время выполнения, в соответствии с документы:

Эту функцию можно использовать для определения собственного способа обработки ошибок во время выполнения.

Предупреждение об устаревании, которое вы видите, реализовано во время компиляции., что по определению происходит перед выполнением:

static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
{
    if (ast->attr == ZEND_DIM_ALTERNATIVE_SYNTAX) {
        zend_error(E_DEPRECATED, "Array and string offset access syntax with curly braces is deprecated");
    }
    ...

Вы можете думать об этом как о «мягкой синтаксической ошибке»: она обнаруживается при синтаксическом анализе, на этапе компиляции, но это не фатальная ошибка, а предупреждение о будущей гибели. Как и синтаксические ошибки, у вас есть два способа их обработки: добавление в начало и обработка завершения работы.

Подготовка

$ cat error-handler.php
<?php
set_error_handler(fn(...$args) => var_dump($args));
$ cat try.php
<?php
$b = 'test';
$a = $b{1};
$ php -d auto_prepend_file=error-handler.php try.php
array(5) {
  [0]=>
  int(8192)
  [1]=>
  string(69) "Array and string offset access syntax with curly braces is deprecated"
  [2]=>
  string(21) "/Users/bishop/try.php"
  [3]=>
  int(3)
  [4]=>
  NULL
}

Обработка отключения

register_shutdown_function(fn() => var_dump(error_get_last()));

$b = 'test';
$a = $b{1};

Выходы:

array(4) {
  ["type"]=>
  int(8192)
  ["message"]=>
  string(69) "Array and string offset access syntax with curly braces is deprecated"
  ["file"]=>
  string(9) "/in/212CF"
  ["line"]=>
  int(7)
}

Что использовать?

Выберите один или оба, в зависимости от ваших потребностей. Лично я использую подход prepend, так как он обрабатывает различные другие сценарии белого экрана смерти. Если вы делаете это в веб-контексте, вам нужно настроить свой веб-сервер для установки параметра auto_prepend_file: после запуска вашего «основного» кода вы не можете установить prepend и заставить его работать, как показано здесь.

person bishop    schedule 07.01.2020
comment
Отличный ответ; что флажок перед добавлением довольно хорош знать о, и это также имеет смысл. Это также намного лучше, чем обратный вызов выключения, который перехватывает только последнюю ошибку (особенно в этом случае, поскольку это неблокирующие уведомления). - person Jeto; 07.01.2020