Подтвердить что ты не робот

Есть ли дамп стека довольно печати?

Скажем прямо, debug_backtrace() не очень debug_backtrace(). Кто-нибудь кодировал обертку?

А какая ваша любимая var_dump() (которую можно использовать в коммерческих проектах, поэтому нет GPL (хотя с LGPL все в порядке))

Смотрите также: Более симпатичная/информативная альтернатива Var_dump в PHP?


Шесть лет - и десять тысяч просмотров этого вопроса - позже, и я все еще использую это. Это не очень хорошо выглядит на экране, как Kint (что отлично).

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

/**
 * @brief Returns an HTML formatted string showing details of the backtrace
 * 
 * Example:
 * 
 *    F:\Dropbox\programs\Xampp\htdocs\api\q.php:48 e(373, 'beer', 'curry')
 *    F:\Dropbox\programs\Xampp\htdocs\api\q.php:53 d(26366, 28255, 8364)
 *    F:\Dropbox\programs\Xampp\htdocs\api\q.php:58 c()
 *    F:\Dropbox\programs\Xampp\htdocs\api\q.php:63 b(1283, 15488, 29369)
 *    F:\Dropbox\programs\Xampp\htdocs\api\q.php:72 a(788, 6077, 25010)
 */
function FormatBacktrace()
{
   $result = '<h4>Backtrace</h4>';

   foreach (debug_backtrace() as $trace)
   {
      if ($trace['function'] ==__FUNCTION__)
          continue;

      $parameters = is_array($trace['args']) ? implode(", ",$trace['args']) : "";

      if (array_key_exists('class', $trace))
         $result .= sprintf("%s:%s %s::%s(%s)<br>",   
                              $trace['file'],   
                              $trace['line'],    
                              $trace['class'],  
                              $trace['function'],  
                              $parameters);
      else
         $result .= sprintf("%s:%s %s(%s)<br>", 
                              $trace['file'], 
                              $trace['line'], 
                              $trace['function'], 
                              $parameters);
    }

    return $result;
}
4b9b3361

Ответ 1

расширение Xdebug может распечатать stacktraces с настраиваемым Степень многословия.

Xdebug stacktrace image

Он также предлагает некоторые дополнительные функции var_dump(), такие как раскраска синтаксиса:

Colored var_dump()

Edit:

Относительно включения Xdebug в коммерческий проект.

лицензия Xdebug имеет всего несколько терминов и кажется довольно разрешительной.

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

  • Попросите конечного пользователя установить Xdebug из дистрибутива Linux или DLL с сайта.
  • Распространять файлы .dll и .so для всех поддерживаемых платформ.
  • Создайте исходный код конечного пользователя
  • Распространение пользовательской сборки PHP

Ответ 2

У вас также есть kint (репозиторий github), у которого есть пакет composer в репозитории packagist

Поэтому либо загрузите библиотеку вручную, либо с помощью composer, это всего лишь вопрос:

$ composer init
$ composer require raveren/kint
$ composer install

Затем вместо ini_set('display_errors', 'On'); я предпочитаю использовать этот простой обработчик в моем основном (первом) включаемом файле:

if (  getenv('__project_env__') === 'DEV') {

  error_reporting(E_ALL | E_STRICT);

  function shutdown_handler() {
    $error = error_get_last();
    Kint::trace();
    Kint::dump($error);
  }
  register_shutdown_function('shutdown_handler');

} else {
 ...
}

При установке __project_env__ в виртуальном хосте Apache (SetEnv __project_env__ "DEV"), чтобы не загрязнять разные ветки репозитория git, где проект живет элементами конфигурации, которые по сути являются environmental

  • В DEV: я получаю отладку
  • В PROD по умолчанию молчит

Вот скриншот того, как выглядит трассировка (каждый шаг является разборным):

Kint stack trace
(источник: github.io)

Ответ 3

Вот моя симпатичная оболочка для печати, предназначенная для вывода без браузера, то есть журналов ошибок или консоли:

function stackTrace() {
    $stack = debug_backtrace();
    $output = '';

    $stackLen = count($stack);
    for ($i = 1; $i < $stackLen; $i++) {
        $entry = $stack[$i];

        $func = $entry['function'] . '(';
        $argsLen = count($entry['args']);
        for ($j = 0; $j < $argsLen; $j++) {
            $func .= $entry['args'][$j];
            if ($j < $argsLen - 1) $func .= ', ';
        }
        $func .= ')';

        $output .= $entry['file'] . ':' . $entry['line'] . ' - ' . $func . PHP_EOL;
    }
    return $output;
}

Ответ 4

jhurliman довольно печатный метод stackTrace выше действительно замечательный. Но для меня это создавало множество PHP-предупреждений, которые также загромождали журнал. Я добавил немного больше ошибок и проверки типов, что приводит к очень хорошей трассировке стека в журналах. Вот модифицированная версия jhurliman кода:

function stackTrace() {
    $stack = debug_backtrace();
    $output = '';

    $stackLen = count($stack);
    for ($i = 1; $i < $stackLen; $i++) {
        $entry = $stack[$i];

        $func = $entry['function'] . '(';
        $argsLen = count($entry['args']);
        for ($j = 0; $j < $argsLen; $j++) {
            $my_entry = $entry['args'][$j];
            if (is_string($my_entry)) {
                $func .= $my_entry;
            }
            if ($j < $argsLen - 1) $func .= ', ';
        }
        $func .= ')';

        $entry_file = 'NO_FILE';
        if (array_key_exists('file', $entry)) {
            $entry_file = $entry['file'];               
        }
        $entry_line = 'NO_LINE';
        if (array_key_exists('line', $entry)) {
            $entry_line = $entry['line'];
        }           
        $output .= $entry_file . ':' . $entry_line . ' - ' . $func . PHP_EOL;
    }
    return $output;
}

Ответ 5

Здесь "pretty print" var_dump

function vdump() {

    $args = func_get_args();

    $backtrace = debug_backtrace();
    $code = file($backtrace[0]['file']);    

    echo "<pre style='background: #eee; border: 1px solid #aaa; clear: both; overflow: auto; padding: 10px; text-align: left; margin-bottom: 5px'>";

    echo "<b>".htmlspecialchars(trim($code[$backtrace[0]['line']-1]))."</b>\n";

    echo "\n";

        ob_start();

            foreach ($args as $arg)
                var_dump($arg);

            $str = ob_get_contents();

        ob_end_clean();

        $str = preg_replace('/=>(\s+)/', ' => ', $str);
        $str = preg_replace('/ => NULL/', ' &rarr; <b style="color: #000">NULL</b>', $str);
        $str = preg_replace('/}\n(\s+)\[/', "}\n\n".'$1[', $str);
        $str = preg_replace('/ (float|int)\((\-?[\d\.]+)\)/', " <span style='color: #888'>$1</span> <b style='color: brown'>$2</b>", $str);

        $str = preg_replace('/array\((\d+)\) {\s+}\n/', "<span style='color: #888'>array&bull;$1</span> <b style='color: brown'>[]</b>", $str);
        $str = preg_replace('/ string\((\d+)\) \"(.*)\"/', " <span style='color: #888'>str&bull;$1</span> <b style='color: brown'>'$2'</b>", $str);
        $str = preg_replace('/\[\"(.+)\"\] => /', "<span style='color: purple'>'$1'</span> &rarr; ", $str);
        $str = preg_replace('/object\((\S+)\)#(\d+) \((\d+)\) {/', "<span style='color: #888'>obj&bull;$2</span> <b style='color: #0C9136'>$1[$3]</b> {", $str);
        $str = str_replace("bool(false)", "<span style='color:#888'>bool&bull;</span><span style='color: red'>false</span>", $str);
        $str = str_replace("bool(true)", "<span style='color:#888'>bool&bull;</span><span style='color: green'>true</span>", $str);

        echo $str;

    echo "</pre>";

    echo "<div class='block tiny_text' style='margin-left: 10px'>";

        echo "Sizes: ";
        foreach ($args as $k => $arg) {

            if ($k > 0) echo ",";
            echo count($arg);

        }

    echo "</div>";

}

Ответ 7

Собираюсь добавить мой ответ на остальные ответы здесь.

Если у вас установлены bootstrap и jquery, он еще более полезен и компактен, но не обязателен.

function prettyPrintBackTrace() {
    $backtrace = "\n<b><u>Full Backtrace</u></b>\n<script>function toggleBackTraceTwirl(self) {\$('span', self).toggleClass('glyphicon-menu-up glyphicon-menu-down');}</script>";
    foreach (debug_backtrace() as $key => $trace) {
        if(($trace['function'] ==__FUNCTION__) || ($trace['function'] == "fail")) {continue;}
        $class = (array_key_exists('class', $trace) ? "class <u>({$trace['class']})</u>" : false);
        $exp = explode("/",$trace['file']);
        $exp[count($exp)-1] = "<b>" . end($exp) . "</b>";;
        $filename = implode("/",array_splice($exp, -4));    
        $backtrace .=  "/{$filename}:{$trace['line']}, ";
        if((isset($trace['args'])) && (is_array($trace['args']))) {


            if( (is_string($trace['args'][0])) && (substr($trace['args'][0],-4) == ".php") && (count($trace['args'] == 1)) ) {
                // It was most likely a php include of some sort.
                $exp = explode("/",$trace['args'][0]);
                $filename = implode("/",array_splice($exp, -2));
                $backtrace .= "function <i>{$trace['function']}(<b>{$filename}</b>)</i>\n";
            } else { 
                // Finish the line and move on.
                $backtrace .= "function <i>{$trace['function']}()</i>&nbsp;<a href='#' data-target='#backtraceparameters{$key}' onClick='toggleBackTraceTwirl(this)' data-toggle='collapse'><span class='glyphicon glyphicon-menu-down'></span></a>\n";
                $backtrace .=  "<div id='backtraceparameters{$key}' class='collapse'>";
                $args = array();
                foreach($trace['args'] as $key => $val) {
                    if($val) $args[(!is_numeric($key) ? "key" : false)] = $val;
                }
                foreach($args as $count =>  $a) {
                    $backtrace .= ($count != (count($args) -1) ? "&boxvr;" : "&boxur;");
                    $value = $a;
                    if($a === true) $value = "<i>true</i>";
                    if($a === false) $value = "<i>f alse</i>";
                    $backtrace .= "&boxh; ".(!is_numeric($count) ? $count." " : false).var_export($value,1)."\n";
                }
                $backtrace .=  "</div>";
            }
        }
    }
    return $backtrace;
}

Я надеюсь, что это помогает кому-то. Я пытался сделать его максимально компактным.

Ответ 8

Мой любимый var_dump фрагмент - это тот, который я сделал много лет назад и с тех пор работаю над совершенствованием. Я знаю, что там есть lib, которые создают действительно симпатичные дампы с аккордеонными меню и все, но я просто хочу простой макет, легко читаемый, может быть, немного HTML и как переносимый, как один метод кода. Таким образом, моя функция:

function preDump() {    //  use string "noEcho" to just get a string return only
    $args = func_get_args();
    $doEcho = TRUE; $sb;
    if ($args) {
        $sb = '<div style="margin: 1em 0;"><fieldset style="display:inline-block;padding:0em 3em 1em 1em;"><legend><b>preDump: '.count($args).' Parameters Found.</b></legend>';
        foreach (func_get_args() as $arg) {
            if (gettype($arg) == 'string') if ($arg == 'noEcho') { $doEcho = FALSE; $sb = preg_replace('/(preDump: )[0-9]+/', 'preDump: '.(count($args)-1), $sb); continue; }
            $sb .= '<pre data-type="'.gettype($arg).'"';
            switch (gettype($arg)) {
                case "boolean":
                case "integer":
                    $sb .= ' data-dump="json_encode"><p style="border-bottom:1px solid;margin:0;padding:0 0 0 1em;"><b>gettype('.gettype($arg).')</b></p><p>';
                    $sb .= json_encode($arg);
                    break;
                case "string":
                    $sb .= ' data-dump="echo"><p style="border-bottom:1px solid;margin:0;padding:0 0 0 1em;"><b>gettype('.gettype($arg).')</b></p><p>';
                    $sb .= $arg;
                    break;
                default:
                    $sb .= ' data-dump="var_dump"';
                    if (is_object($arg)) $sb .= 'data-class="'.get_class($arg).'"';
                    $sb .= '><p style="border-bottom:1px solid;margin:0;padding:0 0 0 1em;"><b>gettype('.gettype($arg).')';
                    if (is_object($arg)) $sb .= ' ['.get_class($arg).']';
                    $sb .= '</b></p><p>';
                    ob_start();
                    var_dump($arg);
                    $sb .= ob_get_clean();
                    if (ob_get_length()) ob_end_clean();
            }
            $sb .= '</p></pre>';
        }
        $sb .= '</fieldset></div>';
    }
    else {
        $sb = '<div style="margin: 1em 0;"><fieldset style="display:inline-block;"><legend><b>preDump: [ERROR]</b></legend><h3>No Parameters Found</h3></fieldset></div>';
    }
    if ($doEcho) echo($sb);
    return $sb;
}

Использование очень просто. Он принимает бесконечные параметры. Кроме того, он показывает все в рамках простого fieldsets для каждого вызванного preDump, а также разделяет каждый параметр на свой собственный тег pre, что делает его чистым и легко читаемым. Каждый тег pre также содержит заголовок, показывающий gettype каждого параметра, и, если он является объектом, он также будет показывать class name.

Используйте так же просто, как var_dump();

preDump(TRUE, 101, 'this is a string', array( 'array', 'here' ), (object)array ( 'this' => 'is', 'an' => 'object' ), $someXMLvariable);

Вы также можете использовать его, чтобы получить дамп в виде простой строки, а затем эхо, если вы считаете нужным:

$bob = preDump($someParam1, $someParam2, 'noEcho'); // 'noEcho' causes it to return as string only