Замолвим слово об отладке и профилировании [PHP]
Все идет от лени. Вы получили чужой очень большой проект в котором нужно сделать небольшие правки, или же написали скрипт и сразу не очевидно, что в нем еще требует оптимизации. Как быть? Читать и анализировать код, выводить каждый шаг на экран или в файл (var_dump() и т.д.) не всегда эффективно, ведь можно воспользоваться средствами отладки, которых на сегодняшний день очень много. Кратко перечислю часто встречающиеся…
Xdebug Debugger and Profiler Tool — расширение PHP. Требует установки на сервер и настройки. Может отображать: стек вызовов функций, распределение памяти. Возможности: профайлинг, анализ покрытия кода, защита от бесконечной рекурсии, интерактивная отладка скриптов. ПО для визуализации логов xdebug: Webgrind – веб-интерфейс для профайлинга Xdebug, написанный на PHP, MacGDBp – Mac OS X клиент, который позволяет отлаживать PHP приложения при помощи Xdebug. Linux GUI kcachegrind. Бесплатный. Интегрируется с многими IDE. См Profiling PHP Applications With xdebug. При включении опции в php.ini:
будет форматировать вывод var_dump() и сообщения об ошибках.
Xhprof — расширение PHP от facebook. Требует установки на сервер и настройки. Позволяет собирать время выполнения каждой функции, использование памяти, время ожидания, количество вызовов и многое другое. Это расширение доступно из репозитория PECL. Почитать документацию можно тут [тыц]. Так же Профилирование и отладка php-приложений с помощью xhprof & FirePHP. Из преимуществ сильно не грузит систему, можно ставить на бой. Бесплатный.
DBG (PHP Debugger and Profiler) — расширение PHP. Требует установки на сервер и настройки. Позволяет работать на тестовом или/и рабочем сервере и отлаживать скрипты локально или удаленно, из IDE или консоли. Платная/бесплатная версии.
ZendDebug — расширение PHP, входит в состав Zend Studio (платная IDE). Требует установки на сервер и настройки. Позволяет практически все тоже, что и xdebug, GUI в IDE Zend Studio или Zend Server. Платный. Чуть ниже рассмотрим его более подробно.
Memtrack — расширение PHP. Позволяет искать утечки памяти. Удобно проверять скрипты запускаемые по крону или в качестве демона. Бесплатный. См. [тыц]
APD Advanced PHP debugger — расширение PHP. Слабый конкурент xdebug, но имеет в себе возможности memtrack. Плохо интегрируется с IDE, однако имеет консольный интерфейс (см. [тыц]). Бесплатный.
DTrace + PHP — расширение PHP. Низкоуровневая отладка. См. [тыц]. Так же не нужно забывать о существовании Strace и прочих системных отладчиков, которые порой способны показать где, так сказать, «собака порылась». Например
strace -p 1111
анализ системных вызов скрипта, с PID=1111. Также сетевые анализаторы wireshark (Windows), ngrep, tcpdump (Linux) — для анализа сетевого трафика, протоколов и т.д.
FirePHP — класс, написан на php + расширение для FireFox. Дает возможность посылать отладочные сообщения в консоль Firebug с помощью вызова php методов. Вся информация посылается через заголовки X-FirePHP-Data, тем самым не пересекаясь с основным контентом страниц. Бесплатный. См. Отладка PHP средствами Firebug
php-console — написан на php + расширение для Google Chrome. Аналог FirePHP, только для Google Chrome, но несколько с другим функционалом. Бесплатный. См. php-console
PHP_Debug класс, написан на php. Помогает в отладке PHP кода, показывает путь выполнения скрипта, отображает все переменные, время выполнения, включенные файлы, выполненные запросы, watch переменные… Эта информация собирается во время выполнения скрипта, и отображается по его завершению и потом может быть использована в любой момент. Бесплатный.
Отладчики в современных CMS/CMF/Framework. Их не рассматриваем, т.к. зачастую они имеют специфику и разработаны под конкретную оболочку, что делает не возможным использование их извне (IDE) или применять без значительных изменений в своих разработках.
Для сбора и анализа узких мест в ваших приложениях иногда может пригодится методика централизованного хранении syslog, см [тыц].
Вернемся к ZendDebug. Так как я в основном пользуюсь Zend Studio, то мне наиболее удобно с ним работать. Он позволяет сразу понять ход выполнения скрипта, поддерживает навигацию по коду из IDE. Не нужны никакие сторонние инструменты, кроме IDE. Это действительно удобно, так сказать настроил один раз и пользуешься.
Отладка и профилирование скриптов в Zend Studio возможна как минимум двумя способами при помощи xdebug или ZendDebug. Только вот профилирование сайта с xdebug у меня не заработало, пишет что нельзя так — только отладка.
Про локальную отладку кода писали еще во времена Zend Studio 5.5 [тыц]. С тех времен мало что изменилось. Но я столкнулся с проблемой, когда web сервер и отлаживаемый код находится на удаленном сервере. Часто такие песочницы закрыты извне, а отрыты только нужные для работы порты. Но если к такой песочнице есть доступ по SSH, то настроить ZendDebug все таки можно, не мешая фаерволу выполнять свою функцию.
Забегая вперед отмечу, что для этого нужно будет создать SSH туннель. Немного о том, зачем SSH туннель нужен в этом случае.
По умолчанию Zend Studio инициирует сеанс удаленной отладки, отправив HTTP запрос на отладочный сервер. Этот запрос содержит параметры обратного адреса (IP-адрес и номер порта), который ZendDebug (установленный на сервере) использует при запуске нового подключения к Zend Studio, чтобы ретранслировать информацию об отладке. Кстати, инициализировать сам сеанс отладки можно как из IDE, так и из браузера установив компонент, поставляемый вместе с Zend Studio, будет довольно удобно.
Обычная отладочная сессия будет иметь место, например, в случае, когда код, WEB сервер и IDE находятся на локальном компьютере.
Но зачастую WEB сервер разделен с IDE брандмауэрами, маршрутизаторами, прокси-серверами т.д. Тут-то и пригодится SSH туннель.
В случае с туннелем процесс установления сеанса отладки состоит из двух основных этапов:
— создания SSH туннеля;
— настройки Zend Debugger, для передачи своего трафика через SSH туннель.
Схема отладочной сессии через SSH туннель примет вид:
Обычная отладочная сессия через SSH туннель
Zend Studio, по умолчанию, открывает порт 10137. Его и будем использовать в примерах далее. Можно назначить и другой порт, если это необходимо.
Создание SSH туннеля в Linux или Mac OS X можно в командной строке:
ssh :127.0.0.1: @пример:
user@workstation:~> ssh -R 10137:127.0.0.1:10137 user@debugserver user@debugserver's password: Welcome to the Debug Server! user@debugserver:~$
Для создания SSH туннеля в Microsoft Windows, можно использовать PuTTY. После создания рабочего SSH соединения, необходимо дополнительно настроить туннель.
Со стороны IDE проверьте, что слушаются порт 10137 и локальный IP адрес 127.0.0.1
Практика тенулирования трафика вам может пригодится и для других целей. Например локальными утилитами делать SQL-дампы СУБД, когда удаленная база разрешает соединение только с 127.0.0.1 и т.д.
Думаю из списка выше каждый сможет найти себе удобный инструмент на каждый день. И что бы разработка приносила еще больше удовольствия, а на вопрос — «Что случилось? Почему лежим?», был всегда оперативный ответ.
Приятной отладки и скриптов без ошибок, спасибо за внимание.
udp. добавил php-console, спасибо Arik
Простой способ отладки программ на PHP
Я пользуюсь этим методом отладки программ на PHP уже лет, наверное, 10. И ещё ни разу он меня не подводил. Почему я решил поделиться этим способом с вами? Наверное потому, что больно смотреть на новичков, которые берут откуда-то код, или пишут приличную портянку сами, он (естественно) не работает и они начинают хаотично менять всё подряд, пытаясь каким-то способом «нащупать» то место, где таится ошибка. Но это на самом деле сложный путь, который не всегда приводит к результату. Итак, вот что я предлагаю.
Главное при отладке программ и поиске «багов» — это терпение и последовательность в действиях. Если вы не будете соблюдать пошаговый алгоритм, то ничего не получится, в итоге вы запутаетесь и ни к чему не придёте.
Сам пошаговый алгоритм сводится к последовательной расстановке меток в программе, обновлению страницы и наблюдению выводимой информации в браузере. Лучше всего начать всего с одной метки.
Каждая метка выглядит примерно так
echo 1; // Отладочная метка exit(); // Завершение работы скрипта
Интерпретатор кода PHP, дойдя до такой метки сделает следующее: выведя «1» в браузер, он немедленно прекратит выполнение кода программы. Таким образом, вы узнаете, что выполнение кода программы дошло до этого места, так как на экране будет выведена единичка и это будет последнее, что отобразится в браузере. Нет ничего проще, чтобы узнать — доходит ли до этой точки интерпретатор.
Вы можете не ставить exit(), если абсолютно уверены в том, что код не обновляет страницу после вывода (нет рефреша).
Дальнейшие действия могут быть следующими:
- Можно переместить отладочную метку по коду ниже, чтобы выяснить — доходит ли интерпретатор до этой точки кода. Очень удобно, если вам надо выяснить факт срабатывания if() или факт входа в метод/функцию.
- Можно выводить не «1», а что-то вроде «#1#» и потом искать его в исходном коде HTML браузера, чтобы не спутать отладочный вывод с обычным выводом (например, если страница содержит кучу других единичек).
- Можно ставить сразу несколько меток в разных точках кода сразу, но эти метки непременно должны быть разные и желательно последовательные. Например, «#1#», «#2#», «#3#» и так далее. Так вы увидите в браузере все метки, до которых дошёл интерпретатор и сможете понять логику, которая в программе сработала.
Общее правило: продвигайтесь по коду очень медленно, стараясь не пропустить того момента, где таится баг. Старайтесь чаще использовать метод половинного деления.
Вывод значений переменных
Но что толку от того, что интерпретатор дошёл или не дошёл до какого-то места? Малоинформативно. Давайте добавим больше жизни!
Часто необходимо вывести значения конкретных переменных в конкретной точке кода. И тут нам пригодятся две мощнейшие функции — print_r() и var_dump(). Вот как их можно использовать.
Для того, чтобы увидеть содержимое переменной, используем print_r($var); или print_r($obj->var) если нужно посмотреть содержимое свойства конкретного объекта. Для того, чтобы увидеть значение true или false, используем var_dump(). Тут необходимо пояснить кое-что. Функция print_r() специально была придумана для того, чтобы красиво выводить значения разных типов. Причём она выводит и целые, и строки, и массивы и даже объекты. А вот true и false она не выводит, то есть вывод всегда будет равен пустой строке. Тут на помощь приходит var_dump(), который выводит точное значение и тип этого значения.
Использовать var_dump() везде я не рекомендую. Вывод, им генерируемый, выглядит намного запутаннее, чем вывод от print_r().
Итого, вот как будет выглядеть наша информативная метка:
echo '#4#'; print_r($var1); print_r($var2); echo '@4@';
Обычно я дублирую номер метки в обрамлении других символов, чтобы видеть, где закончился вывод тестируемых переменных. Это часто бывает полезно.
Можно ещё перед каждым print_r() выводить echo «var=»; чтобы понимать где и чьё значение отображается.
Замер времени выполнения части кода
Очень часто при профайлинге (а ещё чаще при поиске «тормозов» в коде) бывает необходимо замерить реальное время выполнения конкретного куска кода.
В PHP есть замечательная функция microtime(), которая возвращает текущее время в микросекундах. Если ей указать параметр true, то она будет возвращать его в виде числа с плавающей точкой, что нам и нужно.
Идея способа замера времени выполнения куска кода сводится к тому, чтобы запомнить текущее время перед началом этого куска и сравнить его с текущим временем в конце куска. То есть вот так:
$tt0 = microtime(true); // . код, который мы проверяем . $tt1 = microtime(true); echo '#1#='.($tt1-$tt0);
При этом после метки мы увидим время, потраченное на выполнение кода в секундах. Часто вы будете видеть что-то типа такого: 1.233433E-05, это инженерная форма записи очень малых и очень больших чисел. Можно привести её в нормальный вид, добавив функцию sprintf():
Немного больше кода, но зато вы будете видеть нормальные числа вроде 0.000012, т.е. 12 микросекунд.
Вот и всё на сегодня, завтра я напишу специальную статью, в которой расскажу об ещё одном способе отладки с использованием выгрузки лога в файл (бывает полезно, если не хочется нарушать нормальную работу сайта, то есть вывод разных меток на страницу недопустим).
Спасибо за внимание, не забудьте подписаться, чтобы не пропустить очередную статью!