Профилирование и отладка PHP скриптов

Отладка скриптов вообще дело крайне нужное и полезное. Кроме основной задачи — поиска и удаления ошибок, отладка прямо улучшает качество и работоспособность программы в целом. Выловленные баги, исправленная логика — все это делает программу стабильнее в работе, что весьма желанная цель при ее написании. Все ниженаписанное основывается на моем опыте, так что воспринимайте это как мое имхо ))

Итак, какие бывают ошибки и как их можно отловить.

1. Самые простые и самые распространённые — это ошибки, связанные с чудным свойством php — динамической типизацией. Помимо того, что иногда просто упускаешь из виду, что там и в каком формате у тебя хранится, php сам подкидывает сюрпризы вида true при сравнении «qwerty» == 0 и другие чудеса автоматического приведения типов и подобные им брейнфаки.

Если точно известно место, где переменная перестает себя вести, как от нее ожидают, то я особо не мудрствую и ставлю var_dump(переменная). Если догадка подтверждается, то исправляем косяк и идем дальше.

Но не всегда получается определить точное место расхождения значения с ожидаемым. Расхождение это может быть зарыто глубоко в дебри кода, либо наоборот, находится на самом видном месте.

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

Такую красоту довольно трудно отловить руками, особенно в крупных приложениях. Поэтому лучше воспользоваться дебаггером. Во всяких умных книжках довольно часто пишут про APD, хвалят его, но дата его последнего релиза за 2004 год как-то меня настораживает. В багтрекере пишут, что под 5.3 не хочет он работать, у меня из груши не встал, поэтому я забил на него.

Трассировку скрипта можно сделать xdebug’ом. Он часто бывает установлен, но как модуль PHP, а для нормальной работы нужно, чтобы он стоял как Zend module.  По установке все итак расписано в нете, не буду повторяться.

Xdebug генерирует отчет, который показвает последовательно, кто, куда, зачем обратился. Есть специальные парсилки логов, но мне удобнее читать сырые отчеты, потому как в консоли особо красоту не получишь, а через веб я не умею отлаживать. Выдается вот такая красота:

3	67	0	0.013521	394468	drXdebugTraceFileParser->parseLine	1		/home/alex/tmp/trace.php	123	1	$line = '2\t3\t1\t0.000772\t328656\n'
4	68	0	0.013588	394584	explode	0		/home/alex/tmp/trace.php	149	2	'\t'	'2\t3\t1\t0.000772\t328656\n'
4	68	1	0.013630	395376
4	69	0	0.013666	395348	count	0		/home/alex/tmp/trace.php	150	1	array (0 => '2', 1 => '3', 2 => '1', 3 => '0.000772', 4 => '328656\n')
4	69	1	0.013716	395348
4	70	0	0.013757	395436	array_pop	0		/home/alex/tmp/trace.php	178	1	array (0 => '{main}', 1 => 'ini_set')
4	70	1	0.013800	395408
4	71	0	0.013823	395332	drXdebugTraceFileParser->addToFunction	1		/home/alex/tmp/trace.php	180	5	$function = 'ini_set'	$time = 4.3E-5	$memory = 236	$nestedTime = 0	$nestedMemory = 0
5	72	0	0.013900	395376	in_array	0		/home/alex/tmp/trace.php	194

 

Этого достаточно, чтобы проследить логику хода выполнения и отследить косяки. Забыл еще сказать, что xdebug можно подключать на лету. Обычно я выключаю и дебаггер и профайлер в php.ini, а в нужном скрипте просто включаю их вместе или по очереди через

ini_set('xdebug.default_enable', 1);
ini_set('xdebug.profiler_enable', 1);

Это быстро, не нужно никаких дополнительных телодвижений. Xdebug еще можно подключать на кучу разных IDE, даже вроде в денвере он есть.Таким нехитрым образом можно отловить большинство ошибок и невнимательностей в коде. Естественно, что изначально задуманную кривую логику так не исправить.

2. Второй тип ошибок гораздо сложнее отловить. Они также появляются вследствии зевков и невнимательностей, но проявляют себя не сразу, а по наступлению определенных условий. Например, время работы или количество итераций или появление определенного числа в арифметических операциях или наоборот, его непоявление.Еще ошибки могут возникать из-за изменений среды окружения, например форк апача завершил свою сессию и скинул скрипт или крон запускает что-то, что отъело всю память и скрипт просто не может запуститься.

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

Тут приходит на помощь замечательная утилита — strace. Я одно время мучился с тем, что апач раз в 24 часа убивал свои потоки, а с ними и скрипты, из-под которых они были запущены. Так вот был настроен сервер. Нашли ошибку, когда подключились с другого терминала непосредственно к скрипту и слушали его через strace. Там и увидели, что скрипт ловит SIGTERM. Как использовать strace я уже писал. Позволяет исследовать реальную работу скрипта в реальном времени и видит все, что с ним происходит. Вывод можно перенаправить в файл и потом проанализировать. Еще есть схожая утилита, называет ptrace. Все они родные для nix систем. Некоторые чуваки с хабры используют для схожих целей сишный дебаггер. Кому в чем удобней…

3. Третий тип ошибок заключается в том, что память начинает резко утекать куда-то и нужно выяснить куда. Они также возникают из-за невнимательности или усталости и получаются чудеса типа файл инклюдится в бесконечном цикле или переменная набирает и набирает обьемиз-за того, что ее не обнулили предварительно.  Все это конечно можно отловить и через strace, но лучше использовать для этого профайлер xdebug’а.

Также этот способ следует использовать в целях профилактики, чтобы держать под контролем количество вызовов, открытий файлов и размеров переменных. Сам xdebug конечно не отдает все в удобноваримом виде, но под чтение его отчетов есть куча утилит. Я пользуюсь этим скриптом. Он выдает отчеты вида

function            #calls time memory time memory
------------------------------------------------------------
ini_set                  3 0.0002      584 0.0002      584
fix_string               1 0.0010      264 0.0009      184
xdebug_call_file         1 0.0001       48 0.0001       48
xdebug_call_function     1 0.0000       32 0.0000       32
var_dump                 1 0.0002        0 0.0002        0
xdebug_memory_usage      1 0.0000        0 0.0000        0
xdebug_call_line         1 0.0000        0 0.0000        0
{main}                   1 0.0018      480 0.0003     -368

Здесь уже можно отследить и вызовы  и время. Запускаю его обычно в конце работы, чтобы посмотреть, не напортачил ли я чего в коде. Также использую его при оптимизации для оценки результатов

Вот такие нехитрые способы, надеюсь, помогут спасти время и нервы при отладке скриптов. Если есть у кого свои методики — велкам в коменты, буду рад услышать.

P.S. Если кто знает, как завести APD под 5.3, отпишитесь плз!

P.P.S Тут вот чувак просто тру-самурай, целый квест прошел чтобы найти ошибку. Шрифт жесть.

Там строку 967 в файле php_apd.c надо закоментить и все заработает.

И чтобы сделать читалку логов, надо скомпиленную pprofp скопировать в /usr/bin и создать ссылку на php в /usr/local/bin/

3.80 avg. rating (76% score) - 5 votes

18 комментариев

  • а что за зверь KCachegrind?

  • var_dump одна из самых классных функций, на джаве постоянно ищут аналог)

  • dbaik, Kcachegrind — это интерфейс для программы Cachegrind, используемой для профилирования работы программ.

  • Действительно, весьма полезная функция!

  • strace наше все, очень удобно.

  • А мне вот очень интересно, как вы сделали Insert More с условием нажать на твит или g+

    • Плагином wp viral attack

  • Сам стал жертвой динамической типизацией по своей невнимательности. Спасибо за полезне советы!

  • APD… дата его последнего релиза за 2004 год как-то меня настораживает..
    Я бы и не стал связываться — поискал бы что-то анологичное

  • Написав свою первую CMS, не слишком функциональную, но по особому добротную и уютную для себя, в процессе работы понял, что отладка PHP скриптов необходимый атрибут качественной работы системы в целом. Для знакомого, клепающего проги с использованием PHP отладка является основной работой в процессе производства. Говорит, заказчику нужна безупречность…

  • Это такая тема… отладка PHP, у меня бывает волосы начинают потеть… И говорить не хочется, а методы отличные.

  • Многие современные IDE поддерживают Xdebug. И выводят логи в приятном и удобном виде. Напримет нетбинс.

  • Я постоянно из-за невнимательности касячу. Всегда, вообще всегда использую Strace, чего и всем советую, потому что положиться только на человеческий фактор нельзя.

  • Уважаемые,
    я, к сожалению, ни разу не програмист. Просто хобби такое есть — делать небольшие сайтики, но на CMS Joomla, типа как в конструкторе… Так вот, понадобилось в одном php скрипте поменять местами какртинки и текст. Сам я, естствнно, недодумкаю. Может кто-нибуть согласится помочь? Я так думаю, что для специалиста — это минутное дело. Чем могу — тоже помогу при необходимости. Так что если интересно — свистните пжлста на почту dimm.torok( )hotmail.com . Заранее благодарен!

  • Кто откликнулся — спасибо! Разобрался, всё получилось как хотел. Всем удачи во всех начинаниях!

  • Это конечно дурацкая заметка и видимо не понимаю на что указываю, но…

    Профилирование включается одной строкой, а не двумя
    ini_set(‘xdebug.profiler_enable’, 1);
    (тестил на OpenServer-e >>> создает cachegrind.out.[название_скрипта] в папке e:\OpenServer\userdata\temp\xdebug\)

    зачем тогда включать в скрипте / php.ini
    ini_set(‘xdebug.default_enable’, 1);
    если и так все прекрасно работает

    • Наверно потому, что чтобы включить профайлер, надо включить сам xdebug, не?

  • Насчет удобоворимого восприятия лог информации xdebug-а в том же OpenServer (веб-сервер — альтернатива Denwer) есть PHP профайлер в Дополнительно. Жмем на него — прогрузит в браузере Webgrind — ставим 100%, кликаем на Auto (newest) — выбираем нужное исполнение скрипта.

css.php