Почему debug_backtrace() иногда не включает номер строки?

Я нахожу, что иногда debug_backtrace() не включает номер строки для вызова. Есть ли какая-то причина, почему это так, и любой способ исправить это?

Спасибо заранее.

P.S. И да, вызовы, которые он опускает номера строк, это мой собственный код, а не внутренний PHP-код.

Ответ 1

Рассмотрим следующий код:

<?
class BtTest
{
  public function getTheItem()
  {
    var_dump( debug_backtrace( false ) );
    $bt = debug_backtrace( false );
    return $bt[1];
  }

  public function __call( $methodName, $methodArgs )
  {
    return $this->getTheItem();
  }
}

$o = new BtTest();
$bti = $o->test();

assert( 'array_key_exists("function", $bti)' );
assert( 'array_key_exists("line", $bti)' );
assert( 'array_key_exists("file", $bti)' );

Выполнение вышеприведенного примера генерирует следующий вывод:

array(3) {
  [0]=>
  array(6) {
    ["file"]=>
    string(53) "/somewhere/in/the/filesystem/tests/bt-test-so.php"
    ["line"]=>
    int(13)
    ["function"]=>
    string(10) "getTheItem"
    ["class"]=>
    string(6) "BtTest"
    ["type"]=>
    string(2) "->"
    ["args"]=>
    array(0) {
    }
  }
  [1]=>
  array(4) {
    ["function"]=>
    string(6) "__call"
    ["class"]=>
    string(6) "BtTest"
    ["type"]=>
    string(2) "->"
    ["args"]=>
    array(2) {
      [0]=>
      &string(4) "test"
      [1]=>
      &array(0) {
      }
    }
  }
  [2]=>
  array(6) {
    ["file"]=>
    string(53) "/somewhere/in/the/filesystem/tests/bt-test-so.php"
    ["line"]=>
    int(18)
    ["function"]=>
    string(4) "test"
    ["class"]=>
    string(6) "BtTest"
    ["type"]=>
    string(2) "->"
    ["args"]=>
    array(0) {
    }
  }
}
PHP Warning:  assert(): Assertion "array_key_exists("line", $bti)" failed in /somewhere/in/the/filesystem/tests/bt-test-so.php on line 21
PHP Warning:  assert(): Assertion "array_key_exists("file", $bti)" failed in /somewhere/in/the/filesystem/tests/bt-test-so.php on line 22

Первый элемент backtrace (индекс 0) говорит косвенно (через элементы line и file), что метод getTheItem был вызван методом __call.

Второй элемент backtrace (индекс 1) говорит, что метод __call вызывался откуда-то (отсутствовали элементы line и file).

Третий элемент backtrace (индекс 2) говорит, что метод test вызывается из глобальной области script.

Место вызова метода __call, вероятно, находится в коде кода разрешения кода где-то в коде интерпретатора php. Есть две возможности ее фиксации. Либо второй элемент должен ссылаться на файл исходного кода интерпретатора и строку, либо на второй и третий элементы backtrace должны быть объединены в один. Я лично предпочел бы второе решение, поскольку внутренности интерпретатора мне неинтересны (так они кажутся для этого в python traceback), однако я понимаю, что иногда первое решение обеспечивает более явный след (особенно когда это обратный вызов, который вызванный из внутренних элементов).

Так или иначе, кажется, что разработчик (разработчики), ответственный за (или, по крайней мере, поддерживающий) код функции debug_backtrace, не воспринимает его как ошибку или, возможно, не имеет легкого способа его исправить. Было бы нормально заполнить элементы line и file некоторыми значениями держателя места (например, <unknown-file> и 0 или даже null) и подчеркнуть его в документации. Если кто-то не убедит их сделать это, вам просто нужно обработать специальный код в вашем коде.

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

Самый старый отчет - с 2003 года, поэтому вы не должны рассчитывать на быстрое исправление:)

Ответ 2

Я думаю, что это указано как PHP Bug

Отладка backtrace показывает имя файла и lineno вызова script. В случае функция вызывается изнутри внутренняя функция (может быть как обратный вызов) никакие имя файла и lineno не могут быть установлены.

Ответ 3

Независимо от любой "ошибки", "функции", независимо от того, что люди, поддерживающие PHP, хотели бы сказать, debug_backtrace() не работает так, как я ожидал.

Вот мое решение (оно уродливо, но оно работает для меня):

function dbg($msg="")
{
    ob_start();
    debug_print_backtrace(0,1);
    $_ = ob_get_clean();
    list($ignore,$line_number) = explode(':', $_);
    $line_number += 0;

    $backtrace = debug_backtrace(0);
    extract($backtrace[1]);
    echo "<pre>$class::$function($msg) : $line_number</pre>";
}

Функция PHP debug_print_backtrace (0,1); будет производить что-то вроде этого:

# 0 dbg- > ping (290), вызываемый в [/path/to/filename.php:290]

Поскольку это только эхо-трассировка, я должен ob_get_clean() это как строку. Затем я разбираю его.

В моей реализации я хочу знать только класс, функцию, номер строки и, необязательно, строковое сообщение от вызывающей функции. debug_backtrace() обеспечивает класс и функцию правильно, но не номер строки. Вот почему я должен получить номер строки из функции debug_print_backtrace().

Для бонусных очков.... как это работает функция debug_print_backtrace() "знает" номер строки, но debug_backtrace() [время от времени] не делает, а?... это тайна...