Коды ошибок в PHP, их вывод и ловля на живца с помощью недосыпания

Коды ошибок в PHP

От автора: я опять сегодня не выспался! Вчера отлавливал ошибки в написанном скрипте, а сегодня комар жужжал под ухом всю ночь. И кажется, что это насекомое сродни тому багу, который я прошлой ночью еле нашел. В общем, сегодня (раз уж мне не спится) узнаем о кодах ошибок в PHP.

Если их не видно

Причин, почему ошибки не выводятся на экране, может быть несколько:

Их вывод отключен хостером специально – таким образом он заботится о повышении безопасности своего серверного пространства. В том числе и вашего ресурса. И все потому, что в описаниях некоторых ошибок отладчик выводит конфиденциальную информацию. Умелый хакер сможет легко использовать ее для взлома вашего сайта. Например, при указании неправильного пароля при подключении к базе, расположенной на сервере MySQL. В результате на экран выводится описание ошибки, содержащее логин активного пользователя СУБД.

В настройках ядра языка.

Бесплатный курс по PHP программированию

Освойте курс и узнайте, как создать динамичный сайт на PHP и MySQL с полного нуля, используя модель MVC

В курсе 39 уроков | 15 часов видео | исходники для каждого урока

Все эти «частные» случаи мы рассматривали в одном из наших предыдущих материалов. Но так как нами используется Денвер, то я кратко опишу решение данной проблемы в нем.

Перед тем, как найти ошибку коде PHP, сначала нужно ее вывести на экран. Если это не происходит, тогда прямая дорога в php. ini. Здесь нужно активировать значения нескольких параметров:

Данные настройки расположены в разделе «Error handling and logging».

Коды ошибок в PHP

Логов нет!

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

В Денвере данная функция (по умолчанию) отключена. Это можно легко исправить, прописав нужный код в конфигурационном файле (в том же разделе).

Снова откройте php. ini и внесите в него выделенные ниже строки. Точнее, одна из них уже должна быть, но лучше проверить. С помощью этих директив (log_errors и error_log) разрешается запись сообщений обо всех ошибках. А также задается путь к файлу логов, с помощью которого вы сможете осуществить PHP проверку кода на ошибки.

Бесплатный курс по PHP программированию

Освойте курс и узнайте, как создать динамичный сайт на PHP и MySQL с полного нуля, используя модель MVC

В курсе 39 уроков | 15 часов видео | исходники для каждого урока

Коды ошибок в PHP

После редактирования конфигурационного файла перезапустите локальный сервер, чтобы все изменения вступили в силу.

Проверяем

Теперь проверим, что у нас вышло. Для этого запустим умышленную синтаксическую неточность в коде: неправильно объявим переменную PHP.

PHP для начинающих. Обработка ошибок // PHP

О да, в этой статье я поведу свой рассказа об ошибках в PHP, и том как их обуздать.

Ошибки

Разновидности в семействе ошибок

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

Чтобы ни одна ошибка не ушла незамеченной потребуется включить отслеживание всех ошибок с помощью функции error_reporting(), а с помощью директивы display_errors включить их отображение:

Фатальные ошибки

Самый грозный вид ошибок – фатальные, они могут возникнуть как при компиляции, так и при работе парсера или PHP-скрипта, выполнение скрипта при этом прерывается.

E_PARSE
Это ошибка появляется, когда вы допускаете грубую ошибку синтаксиса и интерпретатор PHP не понимает, что вы от него хотите, например если не закрыли фигурную или круглую скобочку:

Или написали на непонятном языке:

Лишние скобочки тоже встречаются, и не важно круглые либо фигурные:

Отмечу один важный момент – код файла, в котором вы допустили parse error не будет выполнен, следовательно, если вы попытаетесь включить отображение ошибок в том же файле, где возникла ошибка парсера то это не сработает:

E_ERROR
Это ошибка появляется, когда PHP понял что вы хотите, но сделать сие не получилось ввиду ряда причин, так же прерывает выполнение скрипта, при этом код до появления ошибки сработает:

Не был найден подключаемый файл:

Было брошено исключение (что это за зверь, расскажу немного погодя), но не было обработано:

При попытке вызвать несуществующий метод класса:

Отсутствия свободной памяти (больше, чем прописано в директиве memory_limit) или ещё чего-нить подобного:

Очень часто происходит при чтении либо загрузки больших файлов, так что будьте внимательны с вопросом потребляемой памяти

Рекурсивный вызов функции. В данном примере он закончился на 256-ой итерации, ибо так прописано в настройках xdebug:

Не фатальные

Данный вид не прерывает выполнение скрипта, но именно их обычно находит тестировщик, и именно они доставляют больше всего хлопот у начинающих разработчиков.

Бывает, если используешь неправильный тип аргументов при вызове функций:

Их очень много, и перечислять все не имеет смысла…

E_NOTICE
Это самые распространенные ошибки, мало того, есть любители отключать вывод ошибок и клепают их целыми днями. Возникают при целом ряде тривиальных ошибок.

Когда обращаются к неопределенной переменной:

Когда обращаются к несуществующему элементу массива:

Когда обращаются к несуществующей константе:

Когда не конвертируют типы данных:

Для избежания подобных ошибок – будьте внимательней, и если вам IDE подсказывает о чём-то – не игнорируйте её:

PHP E_NOTICE in PHPStorm

E_DEPRECATED
Так PHP будет ругаться, если вы используете устаревшие функции (т. е. те, что помечены как deprecated, и в следующем мажорном релизе их не будет):

В моём редакторе подобные функции будут зачёркнуты:

PHP E_DEPRECATED in PHPStorm

Обрабатываемые

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

Отдельно стоит отметить E_USER_DEPRECATED – этот вид всё ещё используется очень часто для того, чтобы напомнить программисту, что метод или функция устарели и пора переписать код без использования оной. Для создания этой и подобных ошибок используется функция trigger_error():

Приручение

Для работы с ошибками в PHP существует 3 функции:

    — устанавливает обработчик для ошибок, которые не обрывают работу скрипта (т. е. для не фатальных ошибок) — получает информацию о последней ошибке — регистрирует обработчик который будет запущен при завершении работы скрипта. Данная функция не относится непосредственно к обработчикам ошибок, но зачастую используется именно для этого

У вас не получится назначить более одной функции для обработки ошибок, хотя очень бы хотелось регистрировать для каждого типа ошибок свой обработчик, но нет – пишите один обработчик, и всю логику отображения для каждого типа описывайте уже непосредственно в нём

С обработчиком, который написан выше есть одна существенная проблема – он не ловит фатальные ошибки, и вместо сайта пользователи увидят лишь пустую страницу, либо, что ещё хуже, сообщение об ошибке. Дабы не допустить подобного сценария следует воспользоваться функцией register_shutdown_function() и с её помощью зарегистрировать функцию, которая всегда будет выполняться по окончанию работы скрипта:

Данная функция будет срабатывать всегда!

Но вернёмся к ошибкам, для отслеживания появления в коде ошибки воспользуемся функцией error_get_last(), с её помощью можно получить информацию о последней выявленной ошибке, а поскольку фатальные ошибки прерывают выполнение кода, то они всегда будут выполнять роль “последних”:

Задание
Дополнить обработчик фатальных ошибок выводом исходного кода файла где была допущена ошибка, а так же добавьте подсветку синтаксиса выводимого кода.

О прожорливости

Проведём простой тест, и выясним – сколько драгоценных ресурсов кушает самая тривиальная ошибка:

В результате запуска данного скрипта у меня получился вот такой результат:

Теперь добавим ошибку в цикле:

Результат ожидаемо хуже, и на порядок (даже на два порядка!):

Вывод однозначен – ошибки в коде приводят к лишней прожорливости скриптов – так что во время разработки и тестирования приложения включайте отображение всех ошибок!

Тестирование проводил на PHP версии 5.6, в седьмой версии результат лучше – 0.0004 секунды против 0.0050 – разница только на один порядок, но в любом случае результат стоит прикладываемых усилий по исправлению ошибок

Где собака зарыта

В PHP есть спец символ «@» – оператор подавления ошибок, его используют дабы не писать обработку ошибок, а положится на корректное поведение PHP в случае чего:

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

Исключения

В эру PHP4 не было исключений (exceptions), всё было намного сложнее, и разработчики боролись с ошибками как могли, это было сражение не на жизнь, а на смерть… Окунуться в эту увлекательную историю противостояния можете в статье Исключительный код. Часть 1. Стоит ли её читать сейчас? Думаю да, ведь это поможет вам понять эволюцию языка, и раскроет всю прелесть исключений

Исключения — исключительные событие в PHP, в отличии от ошибок не просто констатируют наличие проблемы, а требуют от программиста дополнительных действий по обработке каждого конкретного случая.

К примеру, скрипт должен сохранить какие-то данные в кеш файл, если что-то пошло не так (нет доступа на запись, нет места на диске), генерируется исключение соответствующего типа, а в обработчике исключений принимается решение – сохранить в другое место или сообщить пользователю о проблеме.

В каких случаях стоит применять исключения:

Для иллюстрации первого сценария возьмём уже озвученный пример функции для записи данных в файл – помешать нам может очень много факторов, а для того, чтобы сообщить выше стоящему коду в чем именно была проблема необходимо создать и выбросить исключение:

Соответственно ловить данные исключения будем примерно так:

В данном примере приведен очень простой сценарий обработки исключений, когда у нас любая исключительная ситуация обрабатывается на один манер. Но зачастую – различные исключения требуют различного подхода к обработке, и тогда следует использовать коды исключений и задать иерархию исключений в приложении:

Теперь, если использовать эти исключения то можно получить следующий код:

Важно помнить, что Exception — это прежде всего исключительное событие, иными словами исключение из правил. Не нужно использовать их для обработки очевидных ошибок, к примеру, для валидации введённых пользователем данных (хотя тут не всё так однозначно). При этом обработчик исключений должен быть написан в том месте, где он будет способен его обработать. К примеру, обработчик для исключений вызванных недоступностью файла для записи должен быть в методе, который отвечает за выбор файла или методе его вызывающем, для того что бы он имел возможность выбрать другой файл или другую директорию.

Так, а что будет если не поймать исключение? Вы получите “Fatal Error: Uncaught exception …”. Неприятно.
Чтобы избежать подобной ситуации следует использовать функцию set_exception_handler() и установить обработчик для исключений, которые брошены вне блока try-catch и не были обработаны. После вызова такого обработчика выполнение скрипта будет остановлено:

Ещё расскажу про конструкцию с использованием блока finally – этот блок будет выполнен вне зависимости от того, было выброшено исключение или нет:

Для понимания того, что это нам даёт приведу следующий пример использования блока finally :

Т. е. запомните – блок finally будет выполнен даже в том случае, если вы в блоке catch пробрасываете исключение выше (собственно именно так он и задумывался).

Для вводной статьи информации в самый раз, кто жаждет ещё подробностей, то вы их найдёте в статье Исключительный код ;)

Задание
Написать свой обработчик исключений, с выводом текста файла где произошла ошибка, и всё это с подсветкой синтаксиса, так же не забудьте вывести trace в читаемом виде. Для ориентира – посмотрите как это круто выглядит у whoops.

PHP7 – всё не так, как было раньше

Так, вот вы сейчас всю информацию выше усвоили и теперь я буду грузить вас нововведениями в PHP7, т. е. я буду рассказывать о том, с чем вы столкнётесь через год работы PHP разработчиком. Ранее я вам рассказывал и показывал на примерах какой костыль нужно соорудить, чтобы отлавливать критические ошибки, так вот – в PHP7 это решили исправить, но как обычно завязались на обратную совместимость кода, и получили хоть и универсальное решение, но оно далеко от идеала. А теперь по пунктам об изменениях:

Интерфейс Throwable практически полностью повторяет нам Exception :

Сложно? Теперь на примерах, возьмём те, что были выше и слегка модернизируем:

В результате ошибку поймаем и выведем:

TypeError – для ошибок, когда тип аргументов функции не совпадает с передаваемым типом:

ArithmeticError – могут возникнуть при математических операциях, к примеру когда результат вычисления превышает лимит выделенный для целого числа:

AssertionError – редкий зверь, появляется когда условие заданное в assert() не выполняется:

При настройках production-серверов, директивы zend. assertions и assert. exception отключают, и это правильно

Задание
Написать универсальный обработчик ошибок для PHP7, который будет отлавливать все возможные исключения.

При написании данного раздела были использованы материалы из статьи Throwable Exceptions and Errors in PHP 7

Отладка

Иногда для отладки кода нужно отследить что происходило с переменной или объектом на определённом этапе, для этих целей есть функция debug_backtrace() и debug_print_backtrace() которые вернут историю вызовов функций/методов в обратном порядке:

В результате выполнения функции debug_print_backtrace() будет выведен список вызовов приведших нас к данной точке:

Assert

Отдельно хочу рассказать о таком экзотическом звере как assert() в PHP, собственно это кусочек контрактной методологии программирования, и дальше я расскажу вам как я никогда его не использовал :)

Первый случай – это когда вам надо написать TODO прямо в коде, да так, чтобы точно не забыть реализовать заданный функционал:

В результате выполнения данного кода получим E_WARNING :

PHP7 можно переключить в режим exception, и вместо ошибки будет всегда появляться исключение AssertionError :

Второй вариант использования – это создание некоего подобия TDD, но помните – это лишь подобие. Хотя, если сильно постараться, то можно получить забавный результат, который поможет в тестировании вашего кода:

Третий теоретический вариант – это непосредственно контрактное программирование – когда вы описали правила использования своей библиотеки, но хотите точно убедится, что вас поняли правильно, и в случае чего сразу указать разработчику на ошибку (я вот даже не уверен, что правильно его понимаю, но пример кода вполне рабочий):

Никогда не используйте assert() для проверки входных параметров, ведь фактически assert() интерпретирует строковую переменную (ведёт себя как eval() ), а это чревато PHP-инъекцией. И да, это правильное поведение, т. к. просто отключив assert’ы всё что передаётся внутрь будет проигнорировано, а если делать как в примере выше, то код будет выполняться, а внутрь отключенного assert’a будет передан булевый результат выполнения

Если у вас есть живой опыт использования assert() – поделитесь со мной, буду благодарен. И да, вот вам ещё занимательно чтива по этой теме – PHP Assertions, с таким же вопросом в конце :)

Ошибки в PHP

Всем известная истина звучит, что не ошибается только тот, кто ничего не делает. В этой статье мы рассмотрим, какие ошибки бывают, а также кратко рассмотрим функцию error reporting, используемую для контроля отображения errors. Но для начала (in first) изучим каждый вид дефектов отдельно, обратив внимание на наиболее распространенные.

Error в PHP: разновидности

Ошибки в PHP бывают:

Фатальные

Fatal error в PHP — одна из наиболее серьезных проблем. Такие дефекты появляются и при компиляции, и во время работы парсера либо PHP-скрипта. Основной нюанс заключается в том, что происходит прерывание исполнения скрипта.

Ниже рассмотрим основные разновидности фатальных ошибок:

— не удалось обнаружить подключаемый файл PHP;

— было выброшено, но не было обработано исключение;

— разработчик пытался вызвать метод класса, причем данный метод не существует;

— отсутствует свободная память (превышен лимит директивы memory_limit).

Нередко проблема возникает во время чтения либо загрузки больших файлов, поэтому надо быть особенно внимательным в вопросах потребляемой памяти.

Не фатальные

В данном случае выполнение скрипта не прерывается, однако именно эти дефекты часто находят тестировщики программного обеспечения. И именно эти недоработки доставляют наибольшие хлопоты начинающим программистам на PHP.

— обращение к неопределенной переменной;

— обращение к элементу массива, когда элемент не существует;

— обращение к несуществующей константе;

— проблема, возникающая, если не конвертируются типы данных и т. п.

Чтобы избежать таких недоработок, надо быть внимательным, особенно к тому, что подсказывает IDE — игнорировать подсказки точно не стоит;

public function test() <

echo «It’s test for me. It is not fatal error»;

Но вообще тип E_STRICT больше актуален для PHP 5.6, поэтому он практически выпилен из 7-й версии языка.

Пользовательские

Этот «балаган» разводится самим разработчиком. Злоупотреблять такими errors не рекомендуется:

Отдельно надо сказать про E_USER_DEPRECATED — напоминает о том, что метод либо функция устарели, то есть пришло время переписать код. Чтобы создать эту и подобные ошибки, применяется функция trigger_error:

Раз основные разновидности проблем уже были рассмотрены, пришло время дать пояснение относительно работы директивы display_errors:

Error reporting

Функция error reporting является встроенной. Она позволяет контролировать, какие именно errors станут отображаться и сообщаться (reported) разработчику. Не стоит забывать и о том, что в PHP ini существует директива error_reporting, причем во время выполнения функция error_reporting() задает значение этой директивы.

Источники:

https://webformyself. com/kody-oshibok-v-php-ix-vyvod-i-lovlya-na-zhivca-s-pomoshhyu-nedosypaniya/

https://anton. shevchuk. name/php/php-for-beginners-error-handling/

https://otus. ru/journal/oshibki-v-php/

Понравилась статья? Поделиться с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: