Написав собственный обработчик ошибок для системы PHP, я пытаюсь выяснить, как определить, существует ли уровень сообщений об ошибках (который можно получить с помощью Отчет об ошибках()) было глобально установлено на Off (0) или было отключено для этой линии только с помощью @ префикс
В настоящее время проблема заключается в том, что в обоих случаях функция error_reporting () возвращает 0
Обновление № 1
К сожалению, этот пример не работает для PHP 5.3.3 на CentOS 6.8, так как функция ini_get () возвращает то же значение, что и error_reporting ()
function errhandle($errno, $errstr, $errfile, $errline) {
if (error_reporting() === 0 && error_reporting() === (int)ini_get('error_reporting')) {
echo 'error_reporting(0) was used';
} else if (error_reporting() === 0 && error_reporting() !== (int)ini_get('error_reporting')) {
echo '@ was used';
}
}
set_error_handler('errhandle');
echo error_reporting()."\n";
echo @$arr['name'];
// Prints
22527
error_reporting(0) was used
В дополнение к error_reporting()
Вы также можете проверить уровень сообщений об ошибках с помощью ini_get('error_reporting')
, Теоретически это похоже, но есть тонкое отличие, которое делает его ценным для того, что вы пытаетесь сделать.
Если сообщение об ошибке было отключено глобально с error_reporting(0)
затем ini_get('error_reporting')
вернет строку 0
, Но если сообщение об ошибке было оставлено в покое, а в строке был указан префикс @
, он вернет ненулевое значение (значение существующей директивы INI).
Таким образом, вы можете сравнить 2 значения и точно определить, что произошло:
if (error_reporting() === 0 && error_reporting() === (int)ini_get('error_reporting')) {
echo 'error_reporting(0) was used';
} else if (error_reporting() === 0 && error_reporting() !== (int)ini_get('error_reporting')) {
echo '@ was used';
}
Это просто пример того условия, которое вы можете выполнить в своем собственном обработчике ошибок. Если это не совсем то, что вы хотите, дайте мне знать, и я постараюсь настроить это.
Протестировано локально на моем PHP 7.1.2 (CLI на Windows).
Обновление № 1
Немного подумав, я пришел к этой идее. Просто предупреждение, это кажется очень хакерским и неэффективным, но я начинаю думать, что это может быть единственный способ сделать это.
Если вы следуете примеру из документации PHP для set_error_handler, тогда сигнатура функции для вашего пользовательского обработчика ошибок, вероятно, выглядит так:
function myErrorHandler($errno, $errstr, $errfile, $errline)
Другими словами, у вас есть файл и номер строки, где произошла ошибка. Вы можете использовать эту информацию, чтобы открыть сам файл, посмотреть на номер этой строки, разобрать токены и найти @
персонаж. Код будет выглядеть так:
function myErrorHandler($errno, $errstr, $errfile, $errline) {
$errfileContents = file($errfile);
$errlineContents = $errfileContents[$errline - 1];
$tokens = token_get_all('<?php ' . $errlineContents . ' ?>');
if (error_reporting() === 0) {
if (in_array('@', $tokens)){
echo '@ was used';
} else {
echo 'error_reporting(0) was used';
}
}
}
Очевидно, что вы можете расширить это условие, проверив, использовались ли оба метода или ни один из них.
В любом случае, это некрасиво, но у меня работает на моем PHP 5.6.6 (CLI в Windows).
Других решений пока нет …