поиск ошибок в коде php
PHP для начинающих. Обработка ошибок
Не совершает ошибок только тот, кто ничего не делает, и мы тому пример — сидим и трудимся не покладая рук, читаем Хабр 🙂
В этой статье я поведу свой рассказа об ошибках в PHP, и о том как их обуздать.
Ошибки
Разновидности в семействе ошибок
Перед тем как приручать ошибки, я бы рекомендовал изучить каждый вид и отдельно обратить внимание на самых ярких представителей.
Чтобы ни одна ошибка не ушла незамеченной потребуется включить отслеживание всех ошибок с помощью функции error_reporting(), а с помощью директивы display_errors включить их отображение:
Фатальные ошибки
Самый грозный вид ошибок — фатальные, они могут возникнуть как при компиляции, так и при работе парсера или PHP-скрипта, выполнение скрипта при этом прерывается.
E_PARSE
Это ошибка появляется, когда вы допускаете грубую ошибку синтаксиса и интерпретатор PHP не понимает, что вы от него хотите, например если не закрыли фигурную или круглую скобочку:
Или написали на непонятном языке:
Лишние скобочки тоже встречаются, и не так важно круглые либо фигурные:
Отмечу один важный момент — код файла, в котором вы допустили parse error не будет выполнен, следовательно, если вы попытаетесь включить отображение ошибок в том же файле, где возникла ошибка парсера то это не сработает:
E_ERROR
Это ошибка появляется, когда PHP понял что вы хотите, но сделать сие не получилось ввиду ряда причин. Эта ошибка так же прерывает выполнение скрипта, при этом код до появления ошибки сработает:
Не был найден подключаемый файл:
Было брошено исключение (что это за зверь, расскажу немного погодя), но не было обработано:
При попытке вызвать несуществующий метод класса:
Отсутствия свободной памяти (больше, чем прописано в директиве memory_limit) или ещё чего-нить подобного:
Очень часто встречается при чтении либо загрузки больших файлов, так что будьте внимательны с вопросом потребляемой памяти
Рекурсивный вызов функции. В данном примере он закончился на 256-ой итерации, ибо так прописано в настройках xdebug (да, данная ошибка может проявиться в таком виде только при включении xdebug расширения):
Не фатальные
Данный вид не прерывает выполнение скрипта, но именно их обычно находит тестировщик. Именно такие ошибки доставляют больше всего хлопот начинающим разработчикам.
E_WARNING
Бывает, если используешь неправильный тип аргументов при вызове функций:
Их очень много, и перечислять все не имеет смысла…
E_NOTICE
Это самые распространенные ошибки, мало того, есть любители отключать вывод ошибок и клепают их целыми днями. Возникают при целом ряде тривиальных ошибок.
Когда обращаются к неопределенной переменной:
Когда обращаются к несуществующему элементу массива:
Когда обращаются к несуществующей константе:
Когда не конвертируют типы данных:
Для избежания подобных ошибок — будьте внимательней, и если вам IDE подсказывает о чём-то — не игнорируйте её:
E_STRICT
Данный тип ошибок актуален для PHP версии 5.6, и практически все их выпилили из
7-ки. Почитать подробней можно в соответствующей RFC. Если кто знает где ещё остались данные ошибки, то напишите в комментариях
E_DEPRECATED
Так PHP будет ругаться, если вы используете устаревшие функции (т.е. те, что помечены как deprecated, и в следующем мажорном релизе их не будет):
В моём редакторе подобные функции будут зачёркнуты:
Пользовательские
Этот вид, которые «разводит» сам разработчик кода, я уже давно их не встречал, и не рекомендую вам ими злоупотреблять:
Теперь, когда вы познакомились с большинством видов и типов ошибок, пора озвучить небольшое пояснение по работе директивы display_errors :
Приручение
Для работы с ошибками в PHP существует 3 функции:
У вас не получится назначить более одной функции для обработки ошибок, хотя очень бы хотелось регистрировать для каждого типа ошибок свой обработчик, но нет — пишите один обработчик, и всю логику отображения для каждого типа описывайте уже непосредственно в нём
С обработчиком, который написан выше есть одна существенная проблема — он не ловит фатальные ошибки, и при таких ошибках вместо сайта пользователи увидят лишь пустую страницу, либо, что ещё хуже, сообщение об ошибке. Дабы не допустить подобного сценария следует воспользоваться функцией register_shutdown_function() и с её помощью зарегистрировать функцию, которая всегда будет выполняться по окончанию работы скрипта:
Данная функция будет срабатывать всегда!
Но вернёмся к ошибкам, для отслеживания появления в коде ошибки воспользуемся функцией error_get_last(), с её помощью можно получить информацию о последней выявленной ошибке, а поскольку фатальные ошибки прерывают выполнение кода, то они всегда будут выполнять роль «последних»:
Хотел обратить внимание, что данный код хоть ещё и встречается для обработки ошибок, и вы возможно вы даже с ним столкнётесь, но он потерял актуальность начиная с 7-ой версии PHP. Что пришло на замену я расскажу чуть погодя.
О прожорливости
Проведём простой тест, и выясним — сколько драгоценных ресурсов кушает самая тривиальная ошибка:
В результате запуска данного скрипта у меня получился вот такой результат:
Теперь добавим ошибку в цикле:
Результат ожидаемо хуже, и на порядок (даже на два порядка!):
Вывод однозначен — ошибки в коде приводят к лишней прожорливости скриптов — так что во время разработки и тестирования приложения включайте отображение всех ошибок!
Тестирование проводил на различных версиях PHP и везде разница в десятки раз, так что пусть это будет ещё одним поводом для исправления всех ошибок в коде
Где собака зарыта
В PHP есть спец символ «@» — оператор подавления ошибок, его используют дабы не писать обработку ошибок, а положится на корректное поведение PHP в случае чего:
Если вы в такой способ подавляете ошибки, то это уменьшает нагрузку на процессор в сравнении с тем, если вы их просто скрываете (см. сравнительный тест выше), но в любом случае, подавление ошибок это зло
Исключения
В эру PHP4 не было исключений (exceptions), всё было намного сложнее, и разработчики боролись с ошибками как могли, это было сражение не на жизнь, а на смерть… Окунуться в эту увлекательную историю противостояния можете в статье Исключительный код. Часть 1. Стоит ли её читать сейчас? Не могу дать однозначный ответ, лишь хочу заметить, что это поможет вам понять эволюцию языка, и раскроет всю прелесть исключений.
Исключения — исключительные событие в PHP, в отличии от ошибок не просто констатируют наличие проблемы, а требуют от программиста дополнительных действий по обработке каждого конкретного случая.
К примеру, скрипт должен сохранить какие-то данные в кеш файл, если что-то пошло не так (нет доступа на запись, нет места на диске), генерируется исключение соответствующего типа, а в обработчике исключений принимается решение — сохранить в другое место или сообщить пользователю о проблеме.
В каких случаях стоит применять исключения:
Соответственно ловить данные исключения будем примерно так:
В данном примере приведен очень простой сценарий обработки исключений, когда у нас любая исключительная ситуация обрабатывается на один манер. Но зачастую, различные исключения требуют различного подхода к обработке, и тогда следует использовать коды исключений и задать иерархию исключений в приложении:
Теперь, если использовать эти исключения то можно получить следующий код:
Важно помнить, что Exception — это прежде всего исключительное событие, иными словами исключение из правил. Не нужно использовать их для обработки очевидных ошибок, к примеру, для валидации введённых пользователем данных (хотя тут не всё так однозначно). При этом обработчик исключений должен быть написан в том месте, где он будет способен его обработать. К примеру, обработчик для исключений вызванных недоступностью файла для записи должен быть в методе, который отвечает за выбор файла или методе его вызывающем, для того что бы он имел возможность выбрать другой файл или другую директорию.
Чтобы избежать подобной ситуации следует использовать функцию set_exception_handler() и установить обработчик для исключений, которые брошены вне блока try-catch и не были обработаны. После вызова такого обработчика выполнение скрипта будет остановлено:
Ещё расскажу про конструкцию с использованием блока finally — этот блок будет выполнен вне зависимости от того, было выброшено исключение или нет:
Для понимания того, что это нам даёт приведу следующий пример использования блока finally :
Т.е. запомните — блок finally будет выполнен даже в том случае, если вы в блоке catch пробрасываете исключение выше (собственно именно так он и задумывался).
Для вводной статьи информации в самый раз, кто жаждет ещё подробностей, то вы их найдёте в статье Исключительный код 😉
PHP7 — всё не так, как было раньше
Так, вот вы сейчас всю информацию выше усвоили и теперь я буду грузить вас нововведениями в PHP7, т.е. я буду рассказывать о том, с чем вы будете сталкиваться работая над современным PHP проектом. Ранее я вам рассказывал и показывал на примерах какой костыль нужно соорудить, чтобы отлавливать критические ошибки, так вот — в PHP7 это решили исправить, но? как обычно? завязались на обратную совместимость кода, и получили хоть и универсальное решение, но оно далеко от идеала. А теперь по пунктам об изменениях:
Сложно? Теперь на примерах, возьмём те, что были выше и слегка модернизируем:
В результате ошибку поймаем и выведем:
И чуть-чуть деталей:
TypeError — для ошибок, когда тип аргументов функции не совпадает с передаваемым типом:
ArithmeticError — могут возникнуть при математических операциях, к примеру когда результат вычисления превышает лимит выделенный для целого числа:
AssertionError — редкий зверь, появляется когда условие заданное в assert() не выполняется:
При настройках production-серверов, директивы zend.assertions и assert.exception отключают, и это правильно
Полный список предопределённых исключений вы найдёте в официальном мануале, там же иерархия SPL исключений.
При написании данного раздела были использованы материалы из статьи Throwable Exceptions and Errors in PHP 7.
Единообразие
— Там ошибки, тут исключения, а можно это всё как-то до кучи сгрести?
Да запросто, у нас же есть set_error_handler() и никто нам не запретит внутри оного обработчика бросить исключение:
Но данный подход с PHP7 избыточен, со всем теперь справляется Throwable :
Отладка
Иногда, для отладки кода, нужно отследить что происходило с переменной или объектом на определённом этапе, для этих целей есть функция debug_backtrace() и debug_print_backtrace() которые вернут историю вызовов функций/методов в обратном порядке:
В результате выполнения функции debug_print_backtrace() будет выведен список вызовов приведших нас к данной точке:
Assert
Функция assert() поменяла своё поведение при переходе от версии 5.6 к 7.0, и ещё сильней всё поменялось в версии 7.2, так что внимательней читайте changelog’и PHP 😉
Первый случай — это когда вам надо написать TODO прямо в коде, да так, чтобы точно не забыть реализовать заданный функционал:
В результате выполнения данного кода получим E_WARNING :
PHP7 можно переключить в режим exception, и вместо ошибки будет всегда появляться исключение AssertionError :
При необходимости, можно выбрасывать произвольное исключение:
Второй вариант использования — это создание некоего подобия TDD, но помните — это лишь подобие. Хотя, если сильно постараться, то можно получить забавный результат, который поможет в тестировании вашего кода:
Третий вариант — некое подобие на контрактное программирование, когда вы описали правила использования своей библиотеки, но хотите точно убедится, что вас поняли правильно, и в случае чего сразу указать разработчику на ошибку (я вот даже не уверен, что правильно его понимаю, но пример кода вполне рабочий):
Если вас заинтересовали контракты, то специально для вас у меня есть ссылочка на фреймворк PhpDeal.
Никогда не используйте assert() для проверки входных параметров, ведь фактически assert() интерпретирует первый параметр (ведёт себя как eval() ), а это чревато PHP-инъекцией. И да, это правильное поведение, ведь если отключить assert’ы, то все передаваемые аргументы будут проигнорированы, а если делать как в примере выше, то код будет выполняться, а внутрь отключенного assert’a будет передан булевый результат выполнения. А, и это поменяли в PHP 7.2 🙂
Если у вас есть живой опыт использования assert() — поделитесь со мной, буду благодарен. И да, вот вам ещё занимательно чтива по этой теме — PHP Assertions, с таким же вопросом в конце 🙂
В заключение
Я за вас напишу выводы из данной статьи:
Это репост из серии статей «PHP для начинающих»:
Спасибо Максиму Слесаренко за помощь в написании статьи.
Как и какими средствами находить ошибки в PHP коде?
При разработке, порой, код не работает так, как задумано или вообще не работает. Сижу, гадаю: что и где не так?
В итоге часто проблема мелкая, дурацкая опечатка, ошибка в синтаксисе и прочее. Профессионалом так не станешь, если по каждой ерунде бегать по ресурсам. А я хочу им быть.
Вопрос: какие есть способы, чтобы найти ошибки в PHP коде? Какие инструменты, методы, плагины, пути и пр.?
6 ответов 6
Вчера всё работало, а сегодня не работает / Код не работает как задумано
Debugging (Отладка)
В чем заключается процесс отладки? Что это такое?
Процесс отладки состоит в том, что мы останавливаем выполнения скрипта в любом месте, смотрим, что находится в переменных, в функциях, анализируем и переходим в другие места; ищем те места, где поведение отклоняется от правильного.
Будет рассмотрен пример с PHPStorm, но отладить код можно и в любой другой IDE.
Подготовка
Для начала необходимо, чтобы в PHP имелась библиотека для отладки под названием xdebug. Если её еще нет, то надо скачать на xdebug.org.
Далее в php.ini прописываем настройки:
Перезагружаем сервер, на всякий случай.
нажимаем Add new local server
Запуск
В данном случае, т.к. функция вызывается сразу на той же странице, то при нажатии кнопки Debug — отладчик моментально вызовет функцию, выполнение «заморозится» на первом же брейкпойнте. В ином случае, для активации требуется исполнить действие, при котором произойдет исполнение нужного участка кода (клик на кнопку, передача POST-запроса с формы с данными и другие действия).
Процесс
Для самого процесса используются элементы управления (см. изображение выше, выделено зеленым прямоугольником) и немного из дополнительно (см. изображение выше, выделено оранжевым прямоугольником).
Show Execution Point ( Alt+F10 ) — переносит в файл и текущую линию отлаживаемого скрипта. Например, если файлов много, решили посмотреть что в других вкладках, а потом забыли где у вас отладка 🙂
Step Over ( F8 ) — делает один шаг, не заходя внутрь функции. Т.е. если на текущей линии есть какая-то функция, а не просто переменная со значением, то при клике данной кнопки, отладчик не будет заходить внутрь неё.
Step Into ( F7 ) — делает шаг. Но в отличие от предыдущей, если есть вложенный вызов (например функция), то заходит внутрь неё.
Step Out ( Shift+F8 ) — выполняет команды до завершения текущей функции. Удобно, если случайно вошли во вложенный вызов и нужно быстро из него выйти, не завершая при этом отладку.
Rerun ( Ctrl+F5 ) — перезапускает отладку.
Resume Program( F9 ) — продолжает выполнение скрипта с текущего момента. Если больше нет других точек останова, то отладка заканчивается и скрипт продолжает работу. В ином случае работа прерывается на следующей точке останова.
Stop ( Ctrl+F2 ) — завершает отладку.
View Breakpoints ( Ctrl+Shift+F8 ) — просмотр всех установленных брейкпойнтов.
Mute Breakpoints — отключает брейкпойнты.
Итак, в текущем коде видно значение входного параметра:
Дальнейшие нажатия F8 переместят линию кода на строки 11, 12 и, наконец, 15.
Дополнительно
Это удобно, если останов нужен только при определённом значении, а не всегда (особенно в случае с циклами).
Как найти ошибку в своем коде?
2. При работе с БД надо её настраивать так, чтобы она сообщала об ошибках.
Для mysqli, перед коннектом всегда должна быть строчка
Если используется PDO, то соединяться, как написано здесь: http://phpfaq.ru/pdo
5. При проблемах во взаимодействии сервера и клиента (куки, сессии, запросы)- в обязательном порядке смотреть обмен HTTP заголовками
6. Закомментируйте строчку с header(«Location:»), если ищете обшибку в обработчике POST запроса
8. И САМОЕ ВАЖНОЕ: запуская скрипт, смотрите не то, что показывает браузер, а ИСХОДНЫЙ HTML код!.
Программа не работает. Что можно сделать в этом случае?
Даже самый рабочий код, которому ты на 100% доверяешь, и который на соседней машине работает, как часы, может выдавать сообщение об ошибке. Причин тому может быть бесконечное множество. Это и такой распространенный случай, как отсутствие прав доступа к файлам, и такие экзотические, как запрещение провайдером выполнения самых распространенных и безобидных функций.
Во-вторых, убедись, что в коде отсутствуют символы ‘@’ перед именами функций. Этот запрещает вывод сообщения об ошибке. Хорошенькое дело! Ты ошибку ищешь-ищещь, а сам же своей программе рот заткнул.
Следует понимать, что здесь приведён пример, Нереальный. Показан алгоритм действий.
В реальности, при error_reporting(E_ALL); PHP сразу же показал бы, что индекс массива у вас неправильный.
Надеюсь, что я смог хотя бы немного объяснить принципы этого занятия.
Удачной отладки.
Отладка PHP и нахождение ошибок в коде
Автор: beowulf13th · 22 Ноя 2010
Меня запарили спрашивать всякую фигню. Поэтому сейчас расскажу пару способов быстро найти ошибку в коде.
1. Ошибка синтаксиса.
В этом вам поможет любой нормальный редактор с проверкой синтаксиса. Я использую Eclipse SDK с установленным плагином PDT. Замечательно подсвечивает синтаксис PHP, а также HTML, XML и XSL. Слегка работает с JS. Автоподстановка и прочие прелести в комплекте. Требует JRE для работы. Кушает много памяти.
Также ошибки синтаксисы выражаются во всяких загадочных фразах:
unexpected ЧТО-ТО, expecting ЧТО-ТО_ДРУГОЕ or ЕЩЁ_ЧЕГО-НИБУДЬ on line N — намекает нам о том, что там требуется ЧТО-ТО_ДРУГОЕ вместо ЧТО-ТО. Обычно это строка N-1. Например, скобку забыли поставить или точку с запятой.
Вообще слово unexpected переводится как неожиданный. Поэтому если вы это видите — знайте, что-то не там поставили или не дописали. Это как вам должны были выдать зарплату, а выдали мешок яблок. Вот это будет unexpected ‘мешок яблок’ 🙂
Call to undefined function — вы пытаетесь вызвать что-то несуществующее. Может написали prinf(); вместо printf(); ну и всё такое прочее.
Если вдруг у вас ничего не работает, но ничего не выводится, то поставьте параметр error_reporing = E_ALL; Будет отображать все ошибки, включая notice’ы.
Если даже с включенными ошибками у вас ничего не работает вообще — то тут уже надо курить логи апачи и php.
2. Ошибки логики.
Опять-таки надо первым делом включить error_reporting в E_ALL. Иначе уведомления типа: undefined index, undefined variable показываться не будут, и вы долго будете думать, «что ж таки случилось?».
Далее. Если у вас на выходе получается не то, что вы хотите — делайте вывод своей переменной на каждом шаге. Причём не просто через print/echo, а через var_dump(), который покажет вам и тип переменной и всю её начинку.
Я вообще пользуюсь своей версией var_dump() ‘a:
Онлайн-тестеры PHP, JS и CSS кода
Полезные инструменты в складчину программиста, веб-разработчика, тестировщика. Эти онлайн-тестеры помогут протестировать ваш веб-код еще до внедрения на сайте, найти ошибки и «пофиксить» в реальном времени. Есть возможность симулировать любую версию PHP и даже фреймворки, а также протестировать и другой код, например CSS или Java Script.
PHPTester
Позволяет протестировать свой php-код в режиме онлайн прямо в вашем браузере без использования веб-сервера. Поддерживаемые версии PHP: 5.5, 5.6, 7.0
Ссылка: //phptester.net/
PHP Sandbox
Отличается от предыдущего только тем, что дает возможность выбрать любую версию PHP — от 4.4.9 до 7.4.
Ссылка: http://sandbox.onlinephpfunctions.com/
PHP Online Test
Удобный тестер с приятным пользовательским интерфейсом. Содержит в себе много еще других плюшек, например PHP виджеты, API, декодеры/энкодеры. Мне он очень понравился, рекомендую.
Ссылка: //phpfiddle.org/
PHP syntax checker
Осуществляет проверку синтаксиса в PHP-коде. Позволяет загрузить и проверить код из файла. Поддерживает версий PHP: 5.3, 5.4, 5.5, 5.6, 7.1
Ссылка: https://extendsclass.com/php-tester.html
JS.DO — Online JavaScript Editor
Название говорит за себя — этот сервис тестирует ваш JS-код. После регистрации можно указать URL-адрес файла с кодом и проверить в реальном времени, не выходя из браузера. Есть возможность симулировать фреймворки — jQuery, Bootstrap.
Ссылка: https://js.do/
CSSDesk
Замечательный онлайн-сервис. Позволяет поэкспериментировать с CSS-кодом в реальном времени и сразу просматривать результат. Готовый код вы можете скачать. А главное, сервис простой и дружелюбный. Новичку, однозначно понравится!