Стандартное поведение PHP при возникновения ошибки в скрипте
сильно зависит от нескольких параметров конфигурации, обычно задаваемых в php.ini.
Параметр display_errors (on или off) указывает, следует ли отображать сообщения
об ошибках в браузере.
Параметр log_errors (on или off) заставляет PHP записывать сообщения в
файл журнала (в mod_php по умолчанию это error_log, т.е. стандартный лог Apache для хранения
сообщений об ошибках).
Директива error_reporting определяет, в каких случаях
следует генерировать предупреждение, а в каких его можно проигнорировать.
Данные параметры можно выставлять не только в php.ini, но также и прямо во время работы скрипта,
используя функцию ini_set().
Хорошо зарекомендовавший себя стиль заключается в следующем.
При разработке и отладке сайта на тестовом сервере включать display_errors и отключать — log_errors.
Это позволяет программисту максимально быстро реагировать на возникновение ошибочной ситуации, минимизируя число
«переключений между окнами».
При запуске сайта на «боевом» сервере в Интернете — наоборот, отключать display_errors, но включать
log_errors. С одной стороны, это усложнит жизнь злоумышленникам, которые уже не смогут увидеть отладочную
информацию. С другой — в критической ситуации поможет вам понять, что именно произошло, и исправить ошибку,
даже если она не воспроизводится в тестовом окружении.
В обоих случаях error_reporting удобно выставлять в максимально «подробное» состояние — E_ALL,
заставляющее PHP сообщать о самых незначительных оплошностях в коде.
Не стоит путать понятия «сообщение об ошибке» и «ошибка». Сообщение об ошибке — друг и союзник программиста, а не его враг. Чем больше
сообщений мы видим, и чем более подробно они выводятся, тем проще нам отлаживать свои программы.
2. Отладочная информация
Используя одни лишь сообщения об ошибках и предупреждения, можно значительно ускорить отладку скриптов.
Однако во многих случаях этого оказывается недостаточно: приходится по ходу работы сайта выводить еще какую-то
информацию — «отладочные сообщения». Например, значения, принимаемые переменными программы
в тех или иных ситуациях, лог SQL-запросов или статистика по времени работы отдельных участков скрипта.
Возникает вопрос: куда выводить весь этот «хлам»?
Отображать диагностику прямо в браузер плохо: внешний вид HTML-страницы (верстка) от этого может сильно
пострадать. К тому же вам придется все время включать в своем мозгу «блок распознавания образов», отделяя
отладочные сообщения от текстов сайта.
Писать отладочную информацию в логи сервера (или в отдельный файл журнала) тоже не очень удобно: придется
постоянно переключаться между окном браузера и окном просмотра журнала, «чистить» лог, искать в нем
особенно интересные места и т. д. Особенно обидно, что часто полезна лишь малая
доля отладочной информации, поэтому для варианта записи в лог-файл мы получим сильное его
разрастание.
3. «Хакерская» консоль
Класс Debug_HackerConsole_Main как раз и предназначен для временного вывода отладочной
информации в виде, не загромождающей окно браузера и логи сервера. Пример его использования:
<?php
// Include library code.
include_once "../../lib/config.php";
require_once "Debug/HackerConsole/Main.php";
// Create & attach hacker conole to HTML output.
new Debug_HackerConsole_Main(true);
// Dump string values.
for ($i=0; $i<10; $i++) {
$sp = str_repeat(' ', $i);
Debug_HackerConsole_Main::out(
"$sp\ti=$i", "Counting", "#008800"
);
}
// Output to default group.
Debug_HackerConsole_Main::out("Usual message");
// Dump random structure.
Debug_HackerConsole_Main::out($_SERVER, "Input");
?>
<html>
<body style="margin:0px; padding:0px">
This is the test page with any text.<br>
Press Ctrl+~ (tilde) to toggle the console.<br>
Move mouse to console message to see its generator
context (file, line, function name).
<hr>
<?show_source(__FILE__)?>
</body>
</html>
Зайдите на страницу этого примера.
Вы увидите обычный HTML-документ. Теперь нажмите комбинацию клавиш Ctrl+~ (символ
«тильда», располагается на клавиатуре слева от клавиши «единица»). Вы увидите, что в верхней части
страницы открылась «хакерская консоль», в которой перечислен весь вывод, осуществленный скриптом
по команде Debug_HackerConsole_Main::out(). Нажав ту же комбинацию еще раз, вы можете убрать
консоль.
4. Основные возможности класса
Ниже перечислены основные возможности класса Debug_HackerConsole_Main.
Вы можете отображать в консоли не только значения скалярных переменных, но также и массивы.
При этом безопасно использовать метод out() даже в обработчике
ob_start(): вы не получите сообщение об «ошибке вложенного
создания буферов», как при вызове известной функции PHP print_r().
Все сообщения, выводимые в консоль, объединяются в группы (второй параметр метода out())
для удобства отображения.
Можно задавать цвет текста выводимых сообщений (третий параметр).
Если навести мышь на некоторое сообщение и немного подождать, на экране «выскочит» подсказка,
в которой будет написано, в каком файле и на какой строке сгенерировано сообщение.
К сожалению, в Mozilla и FireFox размер такого сообщения ограничен. Так что не удивляйтесь, если оно обрежется справа.
Если указать в конструкторе true, то создается новый обработчик выходного потока скрипта,
в котором осуществляется «прикрепление» JavaScript-части консоли. При значении false перехват
потока не осуществляется, и вы должны вручную «прикрепить» консоль к тексту страницы, используя
метод attachToHtml().
В скрипте можно создавать несколько консолей, сохраняя созданные по new объекты. По умолчанию
(при статическом вызове метода out() вида Debug_HackerConsole_Main::out() используется последняя
созданная консоль. Конечно, вы можете вызывать out() и для произвольного консоль-объекта,
задействовав команду $obj->out(...).
Табуляторы в тексте отладочных сообщений превращаются в корректное число пробелов, так,
как это принято в текстовых редакторах.
Вы можете выделять мышью и копировать в буфер обмена текст из консоли. При дальнейшей вставке
этого текста в любой редактор вы не получите лишних пустых строк или «съеденных» переносов,
как это происходит при использовании стандартных HTML-тэгов <pre> и <xmp>.
5. Упрощение использования консоли
Особенно удобно использовать консоль для вывода лога всех SQL-запросов, выполненных скриптом.
Если работа вашего сайта с СУБД идет через централизованную библиотеку, достаточно добавить
вызов Debug_HackerConsole_Main::out() в функцию, осуществляющую SQL-запрос, чтобы получить
хороший инструмент диагностики (особенно если вы будете логировать не только запросы, но также
и результаты их выполнения в краткой форме вида «запрос возвратил X строк» или «запрос вернул ошибку Y»).
Но, конечно, писать в скриптах Debug_HackerConsole_Main::out() весьма неудобно — слишком длинно. Вы
можете написать функцию с коротким именем (к примеру, debug()), которая будет «переадресовывать»
вызов на метод out(). Однако, если сделать это «в лоб», вы обнаружите, что информация об имени файла и
номере строки, сгенерировавшей сообщение, потерялась: она всегда будет указывать на место определения
функции debug(), а не на место ее вызова.
Специально для того, чтобы решить эту проблему, класс Debug_HackerConsole_Main проверяет, вызван
ли метод out() напрямую или же через call_user_func(). В
последнем случае считается, что выполнена «переадресация», и отображается не контекст вызова out(), а
контекст вызова функции, запустившей out(). В листинге приведен пример создания функции debug(),
отображающей в консоль контекст своего вызова (online-демонстрация).
<?php
// Include library code.
include_once "../../lib/config.php";
require_once "Debug/HackerConsole/Main.php";
new Debug_HackerConsole_Main(true);
// Dump random structure.
debug($_SERVER);
// Mediator function for short call of out() method
function debug($msg)
{
// Use call_user_func_array() to save caller context.
call_user_func(array('Debug_HackerConsole_Main', 'out'), $msg);
}
?>
Press Ctrl+~ (tilde) to toggle the console.<br>
Move mouse pointer to debug message and make sure that
caller context is NOT inside debug() definition, but
points to debug() calling point.
<hr>
<?show_source(__FILE__)?>