Xdebug для PHP-разработчика: пошаговая отладка, брейкпоинты в IDE и поиск причины ошибки
Xdebug — расширение PHP, которое останавливает выполнение скрипта на заданной строке и передаёт его состояние в редактор кода. Разработчик ставит в PhpStorm или VS Code точку останова (брейкпоинт), отправляет запрос и видит значения всех переменных, стек вызовов и ход выполнения строка за строкой. Кроме пошаговой отладки Xdebug умеет профилировать скрипт, собирать покрытие кода тестами и записывать трассировку вызовов. Чтобы всё это заработало, нужно понять режимы расширения, способ запуска сессии и то, как PHP находит IDE, особенно если код работает в Docker.
Содержание

Многие PHP-разработчики обходятся var_dump() и dd(), и для простой страницы этого хватает. Сложности начинаются там, где вывод некуда напечатать: в JSON-API отладочная строка ломает ответ, а обработчик очереди работает в фоне. Xdebug не требует правки кода: вы останавливаете программу в нужный момент, видите весь контекст и тут же проверяете гипотезу, вычислив выражение в окне отладчика.
Как Xdebug находит редактор кода
Не IDE подключается к PHP, а наоборот. По документации о пошаговой отладке, соединение открывает сам Xdebug, когда начинается запрос, и стучится по адресу из настройки xdebug.client_host на порт xdebug.client_port. Обмениваются они по протоколу DBGp, который понимают PhpStorm, VS Code с расширением PHP Debug и другие клиенты. Редактор в это время только слушает порт и ждёт.
Отсюда первая причина, по которой «ничего не происходит». Порт по умолчанию в Xdebug 3 — 9003, а в Xdebug 2 был 9000; руководство по переходу отдельно об этом предупреждает. Старые инструкции из интернета по-прежнему советуют 9000, и если IDE слушает один порт, а Xdebug стучится в другой, брейкпоинты молча пропускаются. Вторая причина — адрес: значение по умолчанию localhost верно, только пока PHP и редактор работают на одной машине.
Режим работы задаётся при старте PHP
Все функции Xdebug 3 включаются одной настройкой xdebug.mode. Значение debug включает пошаговую отладку, develop — расширенный var_dump() и подробные сообщения об ошибках, profile — профилировщик, coverage — сбор покрытия, trace — трассировку вызовов. Режимы сочетают через запятую: debug,develop. По справочнику настроек по умолчанию действует develop, поэтому сразу после установки пошаговая отладка не работает.
Важная деталь из того же справочника: xdebug.mode нельзя задать в файлах .htaccess и .user.ini, которые PHP читает на каждом запросе, а также через php_admin_value в конфигурации пула PHP-FPM. Режим читается один раз при запуске процесса PHP — из php.ini или отдельного файла вроде 99-xdebug.ini — либо берётся из переменной окружения XDEBUG_MODE. На практике это значит, что строка в .user.ini на виртуальном хостинге ничего не включит, а после правки php.ini нужно перезапустить PHP-FPM или веб-сервер. Проверить, что реально действует, проще всего функцией xdebug_info(): она выводит страницу с включёнными режимами и диагностикой подключения.
Вторая настройка, xdebug.start_with_request, решает, когда начинать работу. В режиме debug по умолчанию действует вариант trigger: сессия стартует, только если в запросе есть cookie, GET- или POST-параметр XDEBUG_SESSION или XDEBUG_TRIGGER. Для профилировщика по умолчанию стоит yes, то есть профилируется каждый запрос. Cookie переключает одной кнопкой расширение браузера Xdebug Helper от JetBrains, а для консольного скрипта хватает export XDEBUG_SESSION=1.
Учебный пример: неверная сумма заказа в API
Ситуация учебная. Интернет-магазин отдаёт корзину через JSON-API, и для одного промокода итоговая сумма получается больше, чем без скидки. Вставить var_dump() нельзя: фронтенд перестанет разбирать ответ.
Разработчик включает в PhpStorm прослушивание отладочных соединений, ставит брейкпоинт в начале метода calculateTotal() и отправляет запрос из Postman с cookie XDEBUG_SESSION=1. Выполнение останавливается, в окне Debug видны массив товаров и объект промокода. Чтобы не перебирать тридцать позиций вручную, он делает брейкпоинт условным: остановка только при $item->sku === 'SALE-15'. Командой «шаг с заходом» (F7 в PhpStorm, F11 в VS Code) он попадает в метод applyDiscount() и видит, что скидка приходит строкой "15%", а код умножает цену на 1 + $discount: PHP превращает "15%" в 15 с предупреждением, и цена вырастает в 16 раз.
Важнее самого исправления порядок поиска: остановиться там, где данные уже неверны, и подниматься по стеку вызовов к месту, где они испортились. Результат закрепляют тестом на этот промокод.
Отладка в Docker и на удалённом сервере
В контейнере localhost указывает на сам контейнер, поэтому Xdebug не дотягивается до IDE на вашем компьютере. В Docker Desktop для Windows и macOS работает имя host.docker.internal, его и прописывают в xdebug.client_host. На Linux это имя само по себе не появляется: его добавляют в docker-compose.yml строкой extra_hosts со значением host.docker.internal:host-gateway.
Настройка xdebug.discover_client_host заставляет Xdebug подключаться к адресу, с которого пришёл запрос. Справочник предупреждает: тогда отладочную сессию сможет начать любой, кто достучится до веб-сервера, — на общем стенде это опасно.
Вторая проблема — пути: в контейнере код лежит в /var/www/html, а у вас в папке проекта. В VS Code соответствие задают в launch.json параметром pathMappings — по описанию расширения PHP Debug, он нужен при отладке на другой машине или в контейнере. PhpStorm при первом входящем соединении сам предлагает сопоставить пути. Если соединения нет вовсе, задайте xdebug.log с абсолютным путём к файлу: в журнал попадают адреса и порты, к которым Xdebug пытался подключиться.
С чего начать и в каком порядке осваивать
Шаги ниже идут от простого к сложному не случайно. Почти все жалобы «Xdebug не работает» сводятся к тому, что расширение не загружено, режим не тот или IDE ждёт не на том порту. Если проверить эти три вещи на локальной машине, перенос в Docker сводится к двум настройкам, а не к часам поиска.
- Установите расширение и убедитесь через
php -vилиxdebug_info(), что оно загружено. - Пропишите в
php.iniрежимdebugи перезапустите PHP. - Включите прослушивание в IDE и остановитесь на брейкпоинте в консольном скрипте.
- Повторите то же для веб-запроса с расширением браузера.
- Освойте шаги: обход строки, заход в функцию, выход из неё, условные брейкпоинты и вычисление выражений.
- Перенесите настройку в Docker и проверьте сопоставление путей.
Для тренировки подойдут маленькие задачи: проследить стек вызовов рекурсивной функции, найти отладчиком цикл, который пропускает последний элемент массива, остановиться в обработчике исключения и выяснить, откуда оно пришло. Каждый раз сначала формулируйте гипотезу, а потом проверяйте её.
Если удобнее учиться по программе, Xdebug входит в курс «PHP-разработчик. Базовый уровень» от Skillbox: по обзору, в разделе об отладке разбирают ошибки, исключения, журналы и пошаговое исследование выполнения с Xdebug. Курс рассчитан на три месяца, итоговый проект — облачное хранилище файлов.
Профилирование и покрытие кода
Режим profile отвечает на другой вопрос: не где ошибка, а куда уходит время. По документации профилировщика, Xdebug пишет файлы с именем cachegrind.out. и номером процесса в каталог xdebug.output_dir, по умолчанию /tmp. Открывают их в KCacheGrind на Linux, QCacheGrind на Windows и macOS или прямо в PhpStorm. Файлы бывают огромными, поэтому профилировщик лучше запускать по триггеру.
В профиле, например, видно, что страница каталога тратит время не на шаблон, а на сотни одинаковых запросов к базе внутри цикла. Сам Xdebug замедляет выполнение, поэтому сравнивать стоит доли времени между функциями, а не абсолютные цифры.
Покрытие кода нужно при запуске тестов: команда XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-html coverage строит отчёт о том, какие строки тесты выполнили. Лёгкая альтернатива — расширение PCOV. Его авторы пишут, что разница в скорости с Xdebug заметная, потому что Xdebug как отладчик несёт накладные расходы. Зато покрытие путей выполнения (path coverage) есть только у Xdebug, а при pcov.enabled=1 совместная работа с Xdebug невозможна. Частое решение: PCOV в CI для быстрого отчёта, Xdebug локально для отладки. Даже в режиме off, по справочнику, накладные расходы лишь «близки к нулю», поэтому на рабочем сервере Xdebug не держат вовсе.
На программе «PHP-разработчик с нуля до PRO» инструментам отведено отдельное место: в обзоре профессии «PHP-разработчик с нуля до PRO» от Skillbox среди тем названы «Инструменты: командная строка, отладка и Xdebug». Обучение рассчитано на семь месяцев и включает MySQL и Laravel; подробного плана этого модуля в обзоре нет, его состав стоит уточнить у школы.
Частые ошибки новичков
Первая ошибка — путать конфигурации: php -v в терминале и PHP-FPM, который обслуживает сайт, часто читают разные php.ini, и настройка попадает не туда. Сравните вывод php --ini и страницы xdebug_info() в браузере. Вторая — оставлять start_with_request=yes навсегда: тогда каждый запрос, включая фоновые и консольные, пытается подключиться к IDE и замедляется.
В приложениях на фреймворке отладка устроена так же, но стек вызовов глубже: между маршрутом и вашим контроллером десятки классов ядра. Здесь помогает фильтр, скрывающий в стеке код из vendor. На курсе Skillbox «PHP-фреймворк Laravel», по обзору, отладка и тестирование названы среди тем программы наряду с маршрутами, формами и авторизацией; Xdebug при этом в обзоре прямо не упомянут, поэтому инструменты отладки стоит уточнить у школы.
Как навык влияет на доход
Открытых данных о надбавке за владение Xdebug мы не нашли, и вряд ли они появятся: отладчик почти не встречается в вакансиях отдельной строкой. Он входит в негласный набор, который ожидают от PHP-разработчика уровня middle вместе с Git, Composer, Docker и тестами.
Влияние косвенное. Тот, кто быстро находит причину ошибки в чужом коде, берёт задачи на поддержку старых проектов и разбор инцидентов, а на фрилансе тратит меньше неоплачиваемых часов. Профилирование добавляет задачи по ускорению сайтов. Свою вилку удобнее смотреть по профессии PHP-разработчика в целом, с фильтрами по городу и уровню.
Как выбрать обучение
Отдельных курсов по Xdebug почти нет: его изучают внутри программ по PHP. В описании ищите не слово «отладка», а практику: настройку отладчика с IDE, исключения и журналы, тесты с отчётом о покрытии, Docker.
Сравнить школы, которые учат языку целиком, можно по рейтингу онлайн-школ с обучением PHP. Это рейтинг по языку, а не по отладчику, поэтому перед оплатой спросите у школы, на какой версии PHP и Xdebug идёт обучение и разбирают ли настройку в контейнере.