Все мы делаем ошибки, особенно их бывает трудно найти в таких языках как PHP. Тем более если сервер настроен так, чтобы ошибки не показывались пользователям, я не буду рассказывать как профилировать код с помощью дебагеров, а покажу некоторые фишки, которыми пользуюсь сам.
1. Перехват ошибок
Все функции для дебага мы должны хранить в отдельном файле, ведь они нужны только нам, а не каждому посетителю нашего сайта :). Создадим файл
debug.inc. Так как этот файл мы будем инклюдить только во время дебага, то начнём его с включением вывода всех ошибок:
error_reporting(E_ALL);
Да да, именно всех, даже E_NOTICE, ведь это может быть большой проблемой, если скажем где-то не была передана нужная переменная и PHP её просто создавал на лету. Далее я бы посоветовал перехватывать ошибки и выводить их так, как нам это нравиться.
function userErrorHandler($errno, $errmsg, $filename, $linenum, $vars)
{
$dt = date("Y-m-d H:i:s (T)");
$errortype = array (
E_ERROR => "Error",
E_WARNING => "Warning",
E_PARSE => "Parsing Error",
E_NOTICE => "Notice",
E_CORE_ERROR => "Core Error",
E_CORE_WARNING => "Core Warning",
E_COMPILE_ERROR => "Compile Error",
E_COMPILE_WARNING => "Compile Warning",
E_USER_ERROR => "User Error",
E_USER_WARNING => "User Warning",
E_USER_NOTICE => "User Notice",
E_STRICT => "Runtime Notice"
);
echo '<div style="border:1px solid red;margin:4px;background:#ffe2f0;padding:4px">';
echo $errortype[$errno], ':', $errmsg, ' (FILE:', $filename, ', LINE:', $linenum, ')';
echo '</div>';
}
set_error_handler("userErrorHandler");
2. Собираем статистику
Очень полезно видеть сколько времени выполнялся скрипт, для этого надо записать штамп времени в начале выполнения скрипта и в конце, добавим в наш файл следующий код
function mtime()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
$t1 = mtime();
Так, если в конце выполнения скрипта вывести
mtime() - $t1 то мы получим время его выполнения.
Второе что лично мне очень важно, какие и сколько запросов к базе выполнял мой скрипт. Всю работу с БД я осуществляю через экземпляр одного класса
Recordset; Чтобы не нагромождать наш класс лишними условиями сделаем потомок класса, примерно следующий:
class DebugRecordset extends Recordset
{
public $queries;
function execute($sql)
{
$this->queries[] = $sql;
return parent::execute($sql);
}
function getSingleRow($sql)
{
$this->queries[] = $sql;
return parent::getSingleRow($sql);
}
function open($sql)
{
$this->queries[] = $sql;
return parent::open($sql);
}
}
Таким образом при нормальном режиме мы не будем собирать данные о запросах, так как будем использовать класс Recordset, но при дебаге мы будем использовать именно этот класс и он позволит нам посмотреть список всех запросы, которые были сделаны за время выполнения скрипта.
3. Как показать статистику
Есть много способов, можно выводить это прямо на страницу, делая полный дефейс, можно писать эту информацию в файл или базу, но есть решение, которое мне очень приглянулось. Я использую браузер Firefox, для этого браузера есть замечательный плагин для разработчиков, называется он Firebug. Так вот самое удобное это писать все наши сообщения и статистику в его консоль.
Следующий код выводит нам в консоль всю нашу статистику по времени выполнения, использованной памяти и всех запросах к базе:
function echoConsole($method, $line)
{
$line = str_replace('"', '\"', $line);
echo sprintf(' console.%s("%s");', $method, $line);
}
$m = memory_get_usage();
echo '<script type="text/javascript">';
echo "\nif (('console' in window) && ('firebug' in console)) {\n";
$line = "time: {$t} sec, queries: {$rs->num}, memory: {$m}";
echoConsole('debug', "time: {$t} sec, queries: {$rs->num}, memory: {$m}");
foreach ($rs->queries as $sql)
{
echoConsole('debug', 'QUERY: '.$sql);
}
echo "\n}\n";
echo "</script>\n";
4. А как узнать что начался дебаг
И последняя хитрость, которую я хочу рассказать как понять что надо показывать всю эту информацию именно вам. Можно конечно привязаться к сессии или просто иметь переменную в коде типа
$is_debug, но самое удобное это отслеживать кукисы.
$is_debug = isset($_COOKIE['is_debug']);
И всё, единственное что осталось сделать кнопку “вкл/выкл”, которая будет устанавливать или снимать этот кукис.