TransWikia.com

Как и какими средствами находить ошибки в PHP коде?

Stack Overflow на русском Asked on January 13, 2021

При разработке, порой, код не работает так, как задумано или вообще не работает. Сижу, гадаю: что и где не так?

Час посмотрев на код – иду на проф. ресурсы, например Stack Overflow и публикую вопрос “Где здесь ошибка?” или “Почему не работает?”

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

Вопрос: какие есть способы, чтобы найти ошибки в PHP коде? Какие инструменты, методы, плагины, пути и пр.?

6 Answers

Вчера всё работало, а сегодня не работает / Код не работает как задумано

или

Debugging (Отладка)


В чем заключается процесс отладки? Что это такое?

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

Будет рассмотрен пример с PHPStorm, но отладить код можно и в любой другой IDE.


Подготовка

Для начала необходимо, чтобы в PHP имелась библиотека для отладки под названием xdebug. Если её еще нет, то надо скачать на xdebug.org.

Обычно все библиотеки лежат в папке ext внутри папки PHP. Туда и надо поместить dll.

Далее в php.ini прописываем настройки:

[Xdebug]
zend_extension="C:/server/php/ext/php_xdebug.dll" // <!-- тут свой путь до dll!!!
xdebug.default_enable = 1
xdebug.remote_enable = 1
xdebug.remote_handler = "dbgp"
xdebug.remote_host = "localhost"
xdebug.remote_port = 9000
xdebug.auto_trace = 0

Перезагружаем сервер, на всякий случай.

Теперь если в файле .php написать phpinfo(); то можно будет увидеть в самом низу такую картину:

введите сюда описание изображения

Открываем PHPStorm

  • нажимаем create project from existing files
  • выбираем Web server is installed locally, source files are located under its document root
  • выбираем папку с файлами, и нажав вверху кнопку "Project Root" помечаем папку как корень проекта
  • нажимаем "Next"
  • нажимаем Add new local server

    введите сюда описание изображения

  • вводим имя сервера любое и Web Server root URL. В рассматриваемом примере это http://localhost/testy2

введите сюда описание изображения

  • нажимаем "Next" и затем "Finish"

Запуск

Для начала в левой части панели с кодом на любой строке можно кликнуть ЛКМ, тем самым поставив точку останова (breakpoint - брейкпойнт). Это то место, где отладчик автоматически остановит выполнение PHP, как только до него дойдёт. Количество breakpoint'ов не ограничено. Можно ставить везде и много.

введите сюда описание изображения

Если кликнуть ПКМ и во всплывающем меню выбрать Debug (или в верхнем меню - RunDebug), то при первом запуске PHPStorm попросит настроить интерпретатор. Т.е. надо выбрать версию PHP из папки, где он лежит, чтобы шторм знал, какую версию он будет отлаживать.

введите сюда описание изображения

Теперь можно нажать Debug!!!

В данном случае, т.к. функция вызывается сразу на той же странице, то при нажатии кнопки Debug — отладчик моментально вызовет функцию, выполнение "заморозится" на первом же брейкпойнте. В ином случае, для активации требуется исполнить действие, при котором произойдет исполнение нужного участка кода (клик на кнопку, передача POST-запроса с формы с данными и другие действия).

введите сюда описание изображения

Цифрами обозначены:

  1. Стэк вызовов, все вложенные вызовы, которые привели к текущему месту кода.
  2. Переменные. На текущий момент строки ниже номера 3 ещё не выполнились, поэтому определена лишь $data
  3. Показывает текущие значения любых переменных и выражений. В любой момент здесь можно нажать на +, вписать имя любой переменной и посмотреть её значение в реальном времени. Например: $data или $nums[0], а можно и $nums[i] и item['test']['data'][$name[5]][$info[$key[1]]] и т.д. На текущий момент строки ниже номера 3 ещё не выполнились, поэтому $sum и $output обозначены красным цветом с надписью "cannot evaluate expression".

Процесс

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

введите сюда описание изображения

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 — отключает брейкпойнты.

...

Итак, в текущем коде видно значение входного параметра:

  • $data = "23 24 11 18" — строка с данными через пробел
  • $nums = (4) ["23", "24", "11", "18"] — массив, который получился из входной переменной.

введите сюда описание изображения

Если нажмем F8 2 раза, то окажемся на строке 7; во вкладках Watches и Variables и в самой странице с кодом увидим, что переменная $sum была инициализирована и её значение равно 0.

Если теперь нажмем F8, то попадем внутрь цикла foreach и, нажимая теперь F8, пока не окончится цикл, можно будет наблюдать на каждой итерации, как значения $num и $sum постоянно изменяются. Тем самым мы можем проследить шаг за шагом весь процесс изменения любых переменных и значений на любом этапе, который интересует.

Дальнейшие нажатия F8 переместят линию кода на строки 11, 12 и, наконец, 15.


Дополнительно

Если нажать на View Breakpoints в левой панели, то можно не только посмотреть все брейкпойнты, но в появившемся окне можно еще более тонко настроить условие, при котором на данной отметке надо остановиться. В функции выше, например, нужно остановиться только когда $sum превысит значение 20.

введите сюда описание изображения

Это удобно, если останов нужен только при определённом значении, а не всегда (особенно в случае с циклами).

Correct answer by Алексей Шиманский on January 13, 2021

Файл php.ini может блокировать вывод ошибок. Решение. Проверить параметры error_reporting = E_ALL, display_errors = On, display_startup_errors = On в php.ini. Если вы не знаете где файл php.ini? Используйте php функцию phpinfo(). Откроется таблица. Там есть путь до php.ini. Найдите параметр “Loaded Configuration File” и “Configuration File (php.ini) Path”. Вот здесь я нашел об этом. profi.spage.me/php/show-php-file-errors-enable-php-error-display

Answered by Alex V on January 13, 2021

Все ответы сверху хороши и правильны, но хочется добавить еще пару моментов. Внедрения в проект статического анализатора PHPStan, Phan или Psalm , так же можно использовать все 3 сразу :) Подробней есть статья на хабре тык

Answered by pwnz on January 13, 2021

Нужно начинать с самой большой переменной и спускаться вниз по var_dump();, и найти неверное значение какой-то переменной.

Answered by user316324 on January 13, 2021

Сообщения об ошибках PHP

Как на локальном, так и на боевом сервере необходимо читать и обрабатывать все ошибки. Отличие в том, что на локальном сервере нужно настроить вывод ошибок на экран. На боевом — ошибки НЕ выводить на экран, НО нужно писать в лог, где можно их будет прочитать и проанализировать.

Чтобы вывести все ошибки на экран — надо в самом начале скрипта написать:

ini_set('display_errors',1);
error_reporting(E_ALL ^E_NOTICE);

В данном случае эти строки будут сообщать обо всех критических ошибках на экран. Если никаких ошибок не выведется, надо написать:

error_reporting(E_ALL);

Для вывода ошибок синтаксиса нужно исправить в php.ini (или в .htaccess добавить строчку php_flag display_errors 1).

Итог:

введите сюда описание изображения

введите сюда описание изображения

введите сюда описание изображения

Можно сразу видеть:

  • уровень (предупреждение, уведомление, ошибка)
  • полный текст ошибки
  • имя скрипта с ошибкой
  • номер строки в том самом скрипте

Можно перейти в скрипт на указанную строку и проанализировать.

Не знаете английский?

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

fatal error: uncaught error: call to undefined function getSum() in W:testindex.php on line 6

Фатальная ошибка: неперехваченная ошибка: вызов неопределенной функции getSum() 
в W:testindex.php  в строке 6

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

Answered by Алексей Шиманский on January 13, 2021

Дедовский способ

Не смотря на описанный ниже способ, нужно сразу отметить, что есть замечательные инструменты, которые быстрее помогут обнаружить и исправить ошибки. Одним из них является Интегрированная среда разработки (IDE). Более подробно о ней можно прочитать в вопросе:

Какие есть способы предупреждения ошибок, их нахождения и устранения?


О способе.

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

Используется банально echo/print_r/var_dump. Иногда с добавлением die(), чтобы код не шёл дальше.

Алгоритм действий:

  1. Пишем echo(ИМЯ_ПЕРЕМЕННОЙ) или print_r(ИМЯ_ПЕРЕМЕННОЙ) в одну из точек скрипта. Смотрим, чему равны значения.
  2. Если значения те, какие и ожидаются - ошибка ниже. Удаляем вывод переменных и пишем его ниже.
  3. Если значения не те, какие ожидались, значит проблема выше. Удаляем вывод переменных и пишем его выше.
  4. Повторяем шаги 2 и(или) 3 пока не дойдем до строк, где вывод переменных на строке выше — дает правильный результат, а ниже — нет.

Пример:

$test1 = 3;
$test2 == 2;
$result = $test1 + $test2;
echo $result;

Ожидаем увидеть 5, но видим 3. Напишем

echo '$test1: '.$test1.', $test2: '.$test2.', $result: '.$result;

и видим

$test1: 3, $test2: , $result: 3

$test1 — правильное значение

$test2 и $result — неверные значения. Особенно у $test2

Значит, минимум, проблема в $test2. Если присмотреться, видно, что поставили случайно вместо знака присваивания — знак равно.

$test2 == 2;
        ^------- лишний знак    

Исправляем.

(Заметка) Если код не исполняется в принципе, ничего не выводит, например, то достаточно писать echo 'тестовая_фраза'; в коде и перемещать её выше и выше пока она не появится. Как только надпись появилась, значит понятно, что дело было в строке ниже.

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

Answered by Алексей Шиманский on January 13, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP