Блог о программировании

Ошибки в PHP. Ликбез

Категория: PHP
 17 июня 2016 г. 0:38

Неотъемлемой частью программирования является выявление ошибок в коде. Будь программист хоть семь пядей во лбу, все равно, он будет совершать ошибки, иногда даже банальные. Этому способствует сама природа человека. Поэтому за отладкой и выявлением ошибок в коде программист проводит достаточно большую часть времени. Соответственно, чем гибче и удобнее существуют инструменты для выявления ошибок в коде, и чем лучше программист ими владеет, - тем выше его продуктивность.
Поскольку PHP является скриптовым языком программирования, то все ошибки, допущенные в коде, выявляются по ходу исполнения кода. Программисту PHP предстоит сталкиваться как со стандартными ошибками, присущими программированию в целом, так и с довольно скрытыми ошибками – такими как опечатки в именовании переменных.
Язык PHP предусматривает два механизма выявления ошибок в скрипте в процессе его выполнения: стандартный механизм ошибок PHP и механизм исключений. В PHP множество функционала использует стандартный механизм ошибок, поэтому не знать о нем нельзя. Поэтому в данной статье речь пойдет именно об этом механизме.
Стандартный механизм ошибок PHP довольно прост – если в процессе выполнения сценария интерпретатор PHP сталкивается с какой-либо ошибкой – он пытается известить об этом программиста. Однако настроек этого механизма предусмотрено довольно много, поэтому разобраться в них программисту, познающему PHP, довольно сложно.

Видим ошибки

Так, для того, чтобы PHP отображал ошибки прямо на странице, необходимо установить специальный параметр в коде:
ini_set('display_errors', 1); //display_errors отвечает за отображение ошибок прямиком на странице. Если 0 – ошибки не отображаются
Теперь, при возникновении какой-либо ошибки в скрипте, интерпретатор выведет информацию о ней на странице. Например, если запустить скрипт с несуществующей функцией:
ini_set('display_errors', 1);
echo "

Строка, которая будет отображена

";
echo abrakadabra();
echo "

Строка, которая не будет отображена из-за ошибки

";
то на странице отобразится такая ошибка:
Ошибка
Фатальная ошибка. Такого рода ошибка означает, что скрипт прерывает свою работу, и далее идущий код не будет выполнен.
Отображение ошибок скрипта на странице используется только для отладки самого скрипта, поэтому при запуске кода в боевой среде параметру display_errors устанавливают значение 0.

Категории ошибок
Вообще, в PHP имеется ошибки разных категорий значимости: некоторые из них прерывают дальнейшее выполнение кода – другие нет, одни можно перехватывать – другие нельзя. Полный перечень категорий ошибок приведен ниже:
Значение
Константа
Описание
Возможность
1
E_ERROR
Неустранимая ошибка
Нет
2
E_WARNING
Исправимая ошибка
Да
4
E_PARSE
Ошибка парсера
Нет
8
E_NOTICE
Потенциальная ошибка
Да
16
E_CORE_ERROR
Аналогично E_ERROR, но генерируется ядром PHP
Нет
32
E_CORE_WARNING
Аналогично E_WARNING, но генерируется ядром PHPНет
64
E_COMPILE_ERROR
Аналогично E_ERROR, но генерируется Zend Engine
Нет
128
E_COMPILE_WARNING
Аналогично E_WARNING, но генерируется Zend EngineНет
256
E_USER_ERROR
Аналогично E_ERROR, но инициируется вызовом trigger_error()
Да
512
E_USER_WARNING
Аналогично E_WARNING, но инициируется вызовом trigger_error()Да
1024
E_USER_NOTICE
Аналогично E_NOTICE, но инициируется вызовом trigger_error()Да
2048
E_STRICT
Сообщение от исполнительной среды с рекомендациями по улучшению качества кода (начиная с PHP5)
-
4096
E_RECOVERABLE_ERROR
Опасная, но не фатальная ошибка(например, несоответствие типа)
Да
8192
E_DEPRECATED
Предупреждение об использовании устаревшей функции или возможности
Да
16384
E_USER_DEPRECATED
Предупреждение об использовании устаревшей функции или возможности, инициированное в коде
Да
32767
E_ALL
Все ошибки
Нет
Для удобства предусмотрены константы, которые используются для определения уровня обработки ошибок, построения бит-маски. Константы имеют "говорящие" имена. Глядя на константу - мы можем сказать, что ошибка уровня E_PARSE возникает в случае синтаксической ошибки, E_NOTICE - это напоминание программисту о нарушении "хорошего стиля" программирования на PHP.
По умолчанию включено значение режима генерации сообщений об ошибках E_ALL & ~E_NOTICE, что соответствует выводу всех сообщений, не относящихся к категории E_NOTICE. Программист может гибко настроить, какие категории ошибок ему необходимо видеть на странице. Для того, чтобы изменить режим генерации ошибок, необходимо изменить конфигурационный параметр error_reporting. Чтобы включить отображение любых ошибок, необходимо задать данному параметру значение E_ALL:
ini_set('error_reporting', E_ALL);
Например, если запустить следующий код:
ini_set('display_errors', 1);
ini_set('error_reporting', E_ALL);
$db = mysql_connect($db_host, 'user', 'password');
Мы получим ошибки сразу двух категорий (notice и warning):
Ошибка двух категорий
Когда используется необъявленная переменная – появляется ошибка E_NOTICE. Когда соединение с базой данных MySQL (или другой) завершается неудачей - интерпретатор PHP сообщает об ошибке уровня E_WARNING.

Логируем ошибки
Если даже конфигурационный параметр display_errors установлен в 0, все равно должна быть возможность просматривать наличие случившихся ошибок в процессе выполнения скрипта. Таким образом, в случае если случится ошибка – мы должны знать, где и почему она случилась. Для этих целей в PHP существуют настройки логирования ошибок.
По умолчанию средствами языка PHP ошибки нигде не логируются. Чтобы это изменить, необходимо изменить конфигурационный параметр log_errors в 1 с 0:
ini_set('log_errors', 1);
В таком случае, ошибки автоматически будут записываться в файл, указанный в конфигурационном параметре error_log. Параметр error_log также можно изменить, указав путь к желаемому файлу, куда будут записываться ошибки:
ini_set('error_log', '/var/log/php_errors.log');
Так, для кода:
ini_set('display_errors', 1);
ini_set('error_reporting', E_ALL);
ini_set('log_errors', 1);
ini_set('error_log', __DIR__ . '/log.txt');
$db = mysql_connect($db_host, 'user', 'password');
В лог-файл записывается аналогичная информация, которая выводится на страницу:
[15-Jun-2016 22:47:58] PHP Notice:  Undefined variable: db_host in Z:\home\test\www\index.php on line 7
[15-Jun-2016 22:47:58] PHP Warning: mysql_connect(): Access denied for user 'user'@'localhost' (using password: YES) in Z:\home\test\www\index.php on line 7

Обрабатываем ошибки
Ошибки делятся на перехватываемые и не перехватываемые. Некритические ошибки можно перехватывать пользовательским кодом. Сводная таблица описания категорий ошибок раскрывает информацию, какие категории ошибок можно перехватывать.
Это может быть необходимо, если нужно скорректировать действия при выявлении ошибки. Наиболее частое использование данной возможности – логирование ошибок в собственном формате (читать логи-то нам) и необязательно в файл, а, например, в базу данных.
Для того, чтобы перехватывать некритические ошибки в коде, достаточно реализовать и объявить собственную функцию и передать ее название в функцию set_error_handler. При этом, в реализованную функцию передаются 5 параметров:
  • уровень ошибки в виде целого числа;
  • сообщение об ошибки в виде строки;
  • имя файла, в котором произошла ошибка, в виде строки;
  • номер строки, в которой произошла ошибка, в виде целого числа;
  • массив всех переменных, существующих в области видимости, где произошла ошибка. Причем, будут включены также и глобальные переменные.
Рассмотрим простой код:
ini_set('display_errors', 0);
ini_set('error_reporting', E_ALL);

// объявляем нашу функцию обработки ошибок
function customErrorHandler($errno, $errstr, $errfile, $errline, $variables){
echo "Сторонняя ошибка: [$errno] $errstr
";
echo " Ошибка на строке: $errline; в файле: $errfile
";
}

// устанавливаем нашу функцию обработки ошибок
set_error_handler("customErrorHandler");

$db = mysql_connect($db_host, 'user', 'password'); // тут будут ошибки
На странице получим следующее:
Еще ошибки
Таким образом, видим собственный формат отображения ошибок на странице при выключенном стандартном механизме вывода ошибок. Выходит «те же яйца, только в профиль».

Сами генерируем ошибки
Программист может генерировать следующие категории ошибок - E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE. Другие ошибки генерировать не получится. Для этого существует функция trigger_error() - с её помощью, программист может сообщать пользователю о происшествии так, как это делает PHP.
Как известно из руководства по PHP - функция trigger_error() принимает два параметра:
void trigger_error ( string error_msg [, int error_type]) 
Первый параметр - текстовое сообщение об ошибке, например, "файл не найден". Второй параметр - определяет уровень ошибки(по умолчанию будет E_USER_NOTICE) .
Пример:
ini_set('display_errors', 1);
ini_set('error_reporting', E_ALL);

if (!file_exists('/home/mysite/news.txt')) {
trigger_error('News file not found');
}
В результате получим:
Снова ошибки

Вывод
PHP имеет мощные средства обработки и управления стандартным распространением ошибок. Поэтому отловить ту или иную ошибку не составит труда при условии, что скрипт грамотно сконфигурирован. Знания этой области является неотъемлемыми любого PHP-программиста, поскольку множество кода использует описанный выше механизм

Теги:  php  отладка  php7 

Поделиться статьей

Оставить комментарий