Вот уже 15 лет прошло со времен первого релиза Xdebug. Прекрасный повод вновь представить эту систему миру и объяснить как и почему она делает то что делает.
Xdebug — это расширение для PHP (должно быть скомпилировано и установлено в процессе установки PHP) которое представляет разработчику следующий функционал для отладки:
- Трассировки стека — вывод подробного пути, который привел приложение к полученной ошибке, включая параметры переданные в функции, в порядке позволяющем легко отследить ошибку
- Более приятный вывод var_dump, создающий подсветку кода и структурированный вид вместе с дампом суперглобальных переменных, по аналогии с VarDumper.
- Профайлер для поиска узких мест кода с возможностью визуализированного представления графиков производительности внешними инструментами. В результате получается график похожий на графики из Blackfire.
- Удаленный отладчик, который может быть использован при соединении с Xdebug для запуска и выполнения кода в IDE или браузере построчно через брейк-пойнты.
- “Покрытие кода” которое показывает какая часть кода была выполнена в процессе запроса. Это функция нужна по большей части для юнит-тестов и получения информации о том насколько хорошо ваш код покрыт тестами.
Как мне использовать его?
Xdebug поставляется с подробной инструкцией по установке в которой учтены практически все возможные варианты использования, хотя, если вы хотите поэкспериментировать с представленным ниже функционалом, мы рекомендуем использовать Homestead Improved так как там Xdebug установлен и активирован по умолчанию.
Зачем вообще нужен Xdebug когда есть современные IDE и Blackfire?
Современные IDE предоставляют широкие возможности поиска по коду, так что полезность функционала форматирования ссылок кажется сомнительной. Существуют всевозможные системы логирования способные обрабатывать ошибки и исключения. Также, трассировка и профилирование функций прекрасно реализованы в Blackfire. Не смотря на все это, форматирование ссылок на файлы лишь одна из функций Xdebug, а использование Blackfire связано с собственными трудностями — установка расширения, настройка горячих клавиш, и оплата сохранения истории трассировок. А использование логгеров требует внимательности, так как добавить их в приложение на поздних этапах не самая простая задача.
Но область использования Xdebug не ограничивается лишь этим. Он всё ещё необходим для правильного модульного тестирования (тестируемые фреймворки зависимы от его отчетов о покрытии кода), далеко не так легко провести отладку через удаленные брейк-пойнты другими средствами, а этот инструмент настолько старый и стабильный, что был отшлифован почти до идеала.
Конечно, нет никакой необходимости использовать Xdebug, если ваш текущий инструментарий может обеспечить всё что он предоставляет, или если вам не нужны его возможности, однако у меня не было еще ни одного проекта который можно было бы завершить так же эффективно без его использования.
Давайте попробуем
Предполагается что на этом этапе у вас уже есть среда с работающим Xdebug. Если нет, попробуйте воспользоваться Homestead Improved.
Давайте создадим новый проект состоящий из одного файла index.php и выведем несуществующую переменную $foo:
<?php
echo $foo;
Вот что мы получим:
Отключение Xdebug
Блоки уведомлений подобные этому настолько привычное явление в наше время, что большинство людей даже не понимает что они уже стилизованы с помощью Xdebug. Чтобы доказать это давайте посмотрим как бы это сообщение выглядело без Xdebug. Для отключения Xdebug отредактируем файл /etc/php/7.1/fpm/conf.d/20-xdebug.ini в Homestead Improved, и закомментируем первую строку:
;zend_extension=xdebug.so
xdebug.remote_enable = 1
xdebug.remote_connect_back = 1
xdebug.remote_port = 9000
xdebug.max_nesting_level = 512
После чего нужно перезапустить PHP-FRM:
sudo service php7.1-fpm restart
Примечание: если вы используете среду разработки с другой версией PHP, файл настроек вашего Xdebug скорее всего будет в другом месте. Сверьтесь с документацией системы чтобы найти его или задайте вопрос в комментариях.
Выглядит довольно скудно, не так ли? Из вывода пропал весь стек вызовов. Конечно, пока эта информация не слишком полезна, так как мы работаем только с одной строкой в единственном файле, но позже мы будем использовать ее довольно часто.
Теперь вновь активируем Xdebug, раскомментировав строку в отредактированном ранее файле, и продолжим. Не забудьте перезапустить PHP!
Переходы по файлам
Если у вас есть любимая IDE (у меня, например, PhpStorm), возможность переходить к файлам в ней простым кликом в трассировке стека была бы определенно полезной и значительно увеличила бы скорость отладки. Я продемонстрирую как реализовать эту возможность для PhpStorm.
Давайте снова откроем файл 20-xdebug.ini и добавим в него следующее:
xdebug.file_link_format = phpstorm://open?%f:%l
Заметьте, что не во всех браузерах это будет работать. Например, у Opera возникнут проблемы со ссылкой phpstorm:// и она радостно упадет, в то время как Firefox и Chrome прекрасно обрабатывают такие ссылки.
Если теперь обновить нашу PHP страницу с ошибкой, мы получим ссылки открывающие IDE сразу в точном местоположении ошибки:
Настройка для работы с другими IDE и редакторами происходит точно так же.
Xdebug, Vagrant и PhpStorm
Зачем останавливаться на этом? Многие сегодня используют для разработки виртуальные машины, позволяющие быть уверенным в том что никакая часть из среды исполнения PHP не затронет основную машину, при этом сохраняя всё быстрым и гладким. Как ведет себя Xdebug в таких случаях? Кроме того, возможно ли, в принципе, выполнять отладку с брейк-поинтами, когда вы проходите по своему коду и проверяете каждую строку отдельно?
К счастью, Xdebug отлично поддерживает использование брейк-пойнтов при удаленном соединении. Мы рассмотрели этот процесс выше, а полностью иллюстрированное руководство по настройке вы можете найти в этой статье.
Использование профайлера.
В конце давайте рассмотрим одну из часто игнорируемых функций: профайлер. Для этого нам понадобится какое-нибудь крупное приложение, например Laravel:
composer create-project --prefer-dist laravel/laravel xdebug
И снова нам нужно внести правки в файл 20-xdebug.ini, добавив следующее:
xdebug.profiler_enable_trigger = 1
xdebug.profiler_output_dir = /home/vagrant/Code/
Заметьте — мы не используем xdebug.profiler_enable = 1, так как не хотим чтобы он оставался включенным всё время. Вместо этого мы используем триггерный параметр в запросе “XDEBUG_PROFILE” для выборочной активации. Также мы выводим профиль кэша в основную общую папку нашей виртуальной машины, получая возможность работать с ним в операционной системе хоста.
После перезапуска PHP мы можем проверить это выполнив homestead.app/?XDEBUG_PROFILE (замените homestead.app на имя выбранного вами виртуального хоста или IP-адрес виртуальной машины). Конечно же, файл там где и ожидалось:
В каждой операционной системе есть собственный инспектор кэширования, для OS X, например, можно использовать qcachegring, который легко устанавливается через Homebrew. После установки…
brew install qcachegrind --with-graphviz
… и открытия файла, мы видим удобное разбиение потока выполнения:
Профайлер предоставляет детализированный доступ ко многим данным и возможность досконально изучить поведение вашего кода, также как и в Blackfire. Однако с локальным выводом профайлера намного легче автоматизировать непрерывное отслеживание производительности и сложности выполнения.
Принудительное отображение Xdebug в Laravel
По умолчанию, Laravel имеет собственные отчеты об ошибках и настройки рендеринга. Ошибка, вроде той что мы вызвали ранее с неопределенной переменной, в Laravel будет выглядеть так:
<?php
use IlluminateHttpRequest;
Route::get('/', function(Request $request){
echo $foo;
return view('welcome');
});
Хотя экран ошибок Symfony (который Laravel использует в этом случае) способен так же хорошо работать с переходами Xdebug (попробуйте! Вы можете кликнуть по этим файлам и их строкам!), мне очень не хватает вывода информации о памяти (Xdebug по умолчанию выводит отчет об использовании памяти в каждый момент времени в трассировке). Давайте вернемся к экрану Xdebug в режиме разработки, чтобы отследить этот параметр.
<?php
use IlluminateHttpRequest;
Route::get('/', function(Request $request){
ini_set('display_errors', 1);
restore_error_handler();
echo $foo;
return view('welcome');
});
Как видите мы обновили наш роутинг по умолчанию таким образом, чтобы сначала он активировал отображение ошибок (экран который мы видели ранее не показывает ошибки сразу при появлении, а сохраняет в стек исключений который был позже извлечен и визуализирован), затем мы возвращаем обработчик ошибок в его значение по умолчанию переопределяя значение Laravel.
После обновления, конечно же, вернулся наш старый экран — просто взгляните на эту простыню трассировки стэка и потребления памяти.
Я советую вам продолжить дальнейшее изучение самостоятельно — просмотрите документацию, поиграйте с настройками, выясните сколько всего вы можете узнать о ваших приложениях.
Заключение
Xdebug — ценный инструмент в наборе любого разработчика. Это мощное расширение полностью соответствует своему названию, делая язык, с которым мы ежедневно работаем, более подробным, дружелюбным и менее загадочным при возникновении ошибок.
За 15 лет своего существования Xdebug установил высокие стандарты для отладочных средств. Я хотел бы поблагодарить Дерика за разработку и поддержку всё это время, и буду рад если вы решите написать одно-два руководства об углубленном использовании, подводных камнях или скрытых комбинациях функций о которых никто не задумывался прежде. Давайте поможем его распространению и развитию и в следующие 15 лет.
С днём рождения, Xdebug!
Автор: Mikle