Как дебажить PHP — различия между версиями

Материал из Umicms
Перейти к:навигация, поиск
(¯\_(ツ)_/¯)
 
Строка 85: Строка 85:
  
 
<source lang="php">
 
<source lang="php">
file_put_contents("umitest", print_r($variable, true)."\n", FILE_APPEND | LOCK_EX);
+
file_put_contents("umitest", print_r([__FILE__.' '.__LINE__, $variable], true)."\n", FILE_APPEND | LOCK_EX);
 
</source>
 
</source>
  
В результате выполнения данной функции рядом с файлом, из которого было запущено выполнение PHP (обычно это index.php в корне сайта), будет создан файл umitest в который запишется содержимое переменной $variable.
+
В результате выполнения данной функции рядом с файлом, из которого было запущено выполнение PHP (обычно это index.php в корне сайта), будет создан файл umitest в который запишется имя файла, строка в нем и содержимое переменной $variable.
 +
 
 +
__FILE__ - это волшебная константа PHP которая всегда содержит имя текущего файла.
 +
 
 +
__LINE__ - это волшебная константа PHP которая всегда содержит номер строки в файле в котором она была вызвана.
 +
 
 +
Эти константы рекомендуется добавлять в вывод по нескольким причинам:
 +
 
 +
1) Удобство отслеживания из какого файла и строки в нем была сделана запись
 +
 
 +
2) При отладке большого количества файлов можно забыть куда именно был добавлен отладочный код, эта информация поможет быстро найти его.
  
 
FILE_APPEND - сообщает о том, что данные необходимо записывать в конец файла, без него файл будет каждый раз перезаписываться.
 
FILE_APPEND - сообщает о том, что данные необходимо записывать в конец файла, без него файл будет каждый раз перезаписываться.
Строка 97: Строка 107:
  
 
<source lang="php">
 
<source lang="php">
file_put_contents("umitest", print_r(get_defined_vars(), true)."\n", FILE_APPEND | LOCK_EX);
+
file_put_contents("umitest", print_r([__FILE__.' '.__LINE__, get_defined_vars()], true)."\n", FILE_APPEND | LOCK_EX);
 
</source>
 
</source>
  
Строка 103: Строка 113:
  
 
<source lang="php">
 
<source lang="php">
file_put_contents("umitest", print_r([$var1,$var2], true)."\n", FILE_APPEND | LOCK_EX);
+
file_put_contents("umitest", print_r([__FILE__.' '.__LINE__, $var1, $var2], true)."\n", FILE_APPEND | LOCK_EX);
 
</source>
 
</source>
  
Строка 128: Строка 138:
  
 
<source lang="php">
 
<source lang="php">
file_put_contents("umitest", print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), true), FILE_APPEND | LOCK_EX);
+
file_put_contents("umitest", print_r([__FILE__.' '.__LINE__, debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)], true), FILE_APPEND | LOCK_EX);
 
</source>
 
</source>
  
Строка 141: Строка 151:
 
// тут код время выполнения которого необходимо посчитать
 
// тут код время выполнения которого необходимо посчитать
 
$stop = microtime(true) - $start;
 
$stop = microtime(true) - $start;
file_put_contents("umitest", print_r($stop, true)."\n", FILE_APPEND | LOCK_EX);
+
file_put_contents("umitest", print_r([__FILE__.' '.__LINE__, $stop], true)."\n", FILE_APPEND | LOCK_EX);
 
</source>
 
</source>
  

Версия 14:32, 15 января 2020

Отладка ошибки 500 при помощи register_shutdown_function

Иногда причину 500 ошибки можно определить при помощи вывода последней ошибки, которая произошла перед завершением скрипта. Для ее вывода в начало выполняемого PHP файла необходимо добавить следующий код:

register_shutdown_function(function(){
	if (error_get_last()) {
		var_export(error_get_last());
	}
});

Данный код регистрирует функцию, которая будет выполняться по завершении скрипта. В функции происходит вывод последней ошибки, которая была зафиксирована при выполнении скрипта.

Документация по register_shutdown_function

Вывод данных отладки в браузере

Наиболее простой способ вывести любую переменную это функции print_r(), var_dump() и var_export()

print_r() - выводит структуру переменной в удобочитаемом виде

Документация по print_r

var_dump() - также выводит тип данных для всех переменных

Документация по var_dump

var_export() - выводит структуру переменно в формате пригодным для выполнения в PHP

Документация var_export

По умолчанию выводы этих функций используют '\n' в качестве переносов на новую строку.

Так как в браузере эти символы удаляются, то для того, чтобы результат было удобно читать, можно поместить его в тег <pre>

echo '<pre>';
print_r($var);
echo '</pre>';

или так

echo '<pre>' . print_r($var, true) . '</pre>';

В качестве второго аргумента для функций print_r() и var_export() можно указать true, если необходимо, чтобы функция возвращала результат, а не выводила его.

Код:

echo '<pre>';
print_r($variables['user']);
var_dump($variables['user']);
var_export($variables['user']);
echo '</pre>';

Результат вывода:

Array
(
    [id] => 3
    [type] => guest
)
array(2) {
  ["id"]=>
  int(3)
  ["type"]=>
  string(5) "guest"
}
array (
  'id' => 3,
  'type' => 'guest',
)

Иногда необходимо вывести все доступные в текущей области видимости переменные, в этом случае можно воспользоваться функцией get_defined_vars

Документация по get_defined_vars

Вывод данных отладки в файл

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

Для записи данных отладки в файл нам поможет функция file_put_contents, можно использовать ее со следующими аргументами:

file_put_contents("umitest", print_r([__FILE__.' '.__LINE__, $variable], true)."\n", FILE_APPEND | LOCK_EX);

В результате выполнения данной функции рядом с файлом, из которого было запущено выполнение PHP (обычно это index.php в корне сайта), будет создан файл umitest в который запишется имя файла, строка в нем и содержимое переменной $variable.

__FILE__ - это волшебная константа PHP которая всегда содержит имя текущего файла.

__LINE__ - это волшебная константа PHP которая всегда содержит номер строки в файле в котором она была вызвана.

Эти константы рекомендуется добавлять в вывод по нескольким причинам:

1) Удобство отслеживания из какого файла и строки в нем была сделана запись

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

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

LOCK_EX - блокирует файл для записи, чтобы в него не смогли писать другие скрипты.

Можно вывести в файл все переменные, доступные в текущей области видимости:

file_put_contents("umitest", print_r([__FILE__.' '.__LINE__, get_defined_vars()], true)."\n", FILE_APPEND | LOCK_EX);

или только некоторые из них

file_put_contents("umitest", print_r([__FILE__.' '.__LINE__, $var1, $var2], true)."\n", FILE_APPEND | LOCK_EX);

Документация по file_put_contents

Получить стек вызова функции при помощи debug_backtrace

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

$debug_arr = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)

Также в качестве второго аргумента можно указать глубину стека.

Стек вызова можно вывести как в браузер:

echo '<pre>' . print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), true) . '</pre>';

так и записывать в файл:

file_put_contents("umitest", print_r([__FILE__.' '.__LINE__, debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)], true), FILE_APPEND | LOCK_EX);

Документация по debug_backtrace

Время выполнения скрипта

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

$start = microtime(true);
// тут код время выполнения которого необходимо посчитать
$stop = microtime(true) - $start;
file_put_contents("umitest", print_r([__FILE__.' '.__LINE__, $stop], true)."\n", FILE_APPEND | LOCK_EX);

Документация по microtime