【问题标题】:Why is debug_backtrace() not including line number sometimes?为什么 debug_backtrace() 有时不包括行号?
【发布时间】:2011-06-02 16:34:10
【问题描述】:

我发现有时debug_backtrace() 不包括呼叫的行号。这有什么原因吗?有什么方法可以纠正它吗?

提前致谢。

附:是的,省略行号的调用是我自己的代码,而不是内部 PHP 代码。

【问题讨论】:

  • 有趣。可以举个例子吗?
  • 它是否可能在异常、闭包、评估代码、tick 函数、错误处理程序(基本上任何在正常执行堆栈之外运行的代码)内部?除此之外,我不明白为什么你不会得到行号(至少没有例子)......
  • @deceze - 代码太复杂,无法发布示例。我希望我可以,但可能需要几个小时或更长时间才能确定足够简单的内容以发布,而且我花所有时间都不是什么大问题。

标签: php debugging


【解决方案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

第一个回溯项(索引 0)间接表明(通过 linefile 项)getTheItem 方法是从 __call 方法调用的。

第二个回溯项(索引 1)表示 __call 方法是从某处调用的(缺少 linefile 项)。

第三个回溯项(索引 2)表示 test 方法是从脚本的全局范围调用的。

__call 方法调用的位置可能在 php 解释器代码中的某个方法解析代码中。修复它有两种可能性。第二个项目应该引用解释器的源代码文件和行,或者第二个和第三个回溯项目应该合并为一个。我个人更喜欢第二种解决方案,因为解释器的内部对我来说并不有趣(这就是他们在 python 的回溯中似乎是这样做的),但是我知道有时第一种解决方案提供更明确的跟踪(特别是当它是一个回调时)从内部调用)。

如此左右,似乎负责(或至少维护)debug_backtrace 函数代码的开发人员并不认为它是一个错误,或者可能没有简单的方法来修复它。可以用一些占位符值(例如 &lt;unknown-file&gt;0 甚至 nulls)填充 linefile 项目并在文档中强调它。 除非有人成功说服他们这样做,否则你只需要处理代码中的特殊情况。

我写上面只是为了分享我对函数奇怪行为的理解。如果有人愿意为更美好的世界而奋斗,这里是一些相关错误报告的链接:

最早的报告是 2003 年的,所以你不应该指望快速修复 :)

【讨论】:

    【解决方案2】:

    我认为这被列为PHP Bug

    调试回溯显示文件名和 调用脚本的行号。如果 从内部调用函数 内部函数(可能作为回调) 不能设置文件名和行号。

    【讨论】:

    • 感谢您跟踪该链接。我不认为代码是由内部函数调用的,但我会检查一下。
    【解决方案3】:

    不管有什么“bug”、“特性”,不管维护 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() [偶尔] 不知道,是吗??? ...这是一个谜...

    【讨论】:

      【解决方案4】:

      在检查了各种PHP版本的bugs.php.net上的一堆相关问题后,这个问题似乎已经在PHP 7.0及更高版本上得到修复,包括8.0,它总是提供一个'文件',即使它是假的像从标准输入评估的代码的“标准输入代码”。

      【讨论】:

        猜你喜欢
        • 2021-11-20
        • 2018-10-13
        • 2020-01-09
        相关资源
        最近更新 更多