In ngăn xếp cuộc gọi PHP


Câu trả lời:


123

Nếu bạn muốn tạo một backtrace, bạn đang tìm kiếm debug_backtracevà / hoặc debug_print_backtrace.


Ví dụ, cái đầu tiên sẽ giúp bạn có một mảng như thế này (trích dẫn hướng dẫn) :

array(2) {
[0]=>
array(4) {
    ["file"] => string(10) "/tmp/a.php"
    ["line"] => int(10)
    ["function"] => string(6) "a_test"
    ["args"]=>
    array(1) {
      [0] => &string(6) "friend"
    }
}
[1]=>
array(4) {
    ["file"] => string(10) "/tmp/b.php"
    ["line"] => int(2)
    ["args"] =>
    array(1) {
      [0] => string(10) "/tmp/a.php"
    }
    ["function"] => string(12) "include_once"
  }
}


Họ dường như sẽ không xóa bộ đệm I / O, nhưng bạn có thể tự làm điều đó, với flushvà / hoặc ob_flush.

(xem trang hướng dẫn của trang đầu tiên để tìm hiểu lý do tại sao "và / hoặc" ;-))


7
điều này thường xuyên làm cho php của tôi hết bộ nhớ. Tôi đề nghị giải pháp của Tobiasz.
peedee 16/07/2015

Nếu bạn cảm thấy khó đọc / hiểu, tôi cũng đề xuất giải pháp của Tobiasz
ViliusL

1
@peedee tất cả những gì bạn cần là cung cấp một trong các DEBUG_BACKTRACE_IGNORE_ARGStham số tùy chọn ; điều đó làm cho chúng có chức năng tương đương với(new \Exception())->getTraceAsString()

566

Dễ đọc hơn debug_backtrace():

$e = new \Exception;
var_dump($e->getTraceAsString());

#2 /usr/share/php/PHPUnit/Framework/TestCase.php(626): SeriesHelperTest->setUp()
#3 /usr/share/php/PHPUnit/Framework/TestResult.php(666): PHPUnit_Framework_TestCase->runBare()
#4 /usr/share/php/PHPUnit/Framework/TestCase.php(576): PHPUnit_Framework_TestResult->run(Object(SeriesHelperTest))
#5 /usr/share/php/PHPUnit/Framework/TestSuite.php(757): PHPUnit_Framework_TestCase->run(Object(PHPUnit_Framework_TestResult))
#6 /usr/share/php/PHPUnit/Framework/TestSuite.php(733): PHPUnit_Framework_TestSuite->runTest(Object(SeriesHelperTest), Object(PHPUnit_Framework_TestResult))
#7 /usr/share/php/PHPUnit/TextUI/TestRunner.php(305): PHPUnit_Framework_TestSuite->run(Object(PHPUnit_Framework_TestResult), false, Array, Array, false)
#8 /usr/share/php/PHPUnit/TextUI/Command.php(188): PHPUnit_TextUI_TestRunner->doRun(Object(PHPUnit_Framework_TestSuite), Array)
#9 /usr/share/php/PHPUnit/TextUI/Command.php(129): PHPUnit_TextUI_Command->run(Array, true)
#10 /usr/bin/phpunit(53): PHPUnit_TextUI_Command::main()
#11 {main}"

50
Chết tiệt, cái này tốt hơn nhiều, tại sao họ không thể biến nó thành đầu ra mặc định cho debug_print_backtrace ()? Có thể đã thêm một tham số boolean "returnTrace" cho những người muốn nó trong một biến, không lặp lại, và nó sẽ hoàn hảo!
juggiks

1
Tôi không biết bao nhiêu tháng tôi đã cố gắng tìm ra cách để làm điều đó mà không bao giờ nghĩ rằng nó sẽ hoạt động
WojonsTech

Giải pháp này dường như chiếm ít bộ nhớ hơn so với việc bắt đầu ra của debug_backtrace () dưới dạng một mảng và sau đó in nó bằng print_r (), đó là những gì tôi đã làm cho đến khi tôi thấy điều này!
Peter

5
Tôi đang tìm cách giới hạn debug_backtraceđể chỉ trả về cấp độ đầu tiên trong stacktrace - giải pháp này thực hiện công việc cho tôi. Cảm ơn bạn!
ankr

3
@Andrew print_rsẽ giữ lại tất cả các tin nhắn.
mopo922

41

Để đăng nhập theo dõi

$e = new Exception;
error_log(var_export($e->getTraceAsString(), true));

Cảm ơn @Tobiasz


35

Backtrace đổ rất nhiều rác mà bạn không cần. Nó rất dài, khó đọc. Tất cả những gì bạn muốn là "cái gì gọi là từ đâu?" Đây là một giải pháp chức năng tĩnh đơn giản. Tôi thường đặt nó trong một lớp gọi là 'gỡ lỗi', chứa tất cả các hàm tiện ích gỡ lỗi của tôi.

class debugUtils {
    public static function callStack($stacktrace) {
        print str_repeat("=", 50) ."\n";
        $i = 1;
        foreach($stacktrace as $node) {
            print "$i. ".basename($node['file']) .":" .$node['function'] ."(" .$node['line'].")\n";
            $i++;
        }
    } 
}

Bạn gọi nó như thế này:

debugUtils::callStack(debug_backtrace());

Và nó tạo ra đầu ra như thế này:

==================================================
 1. DatabaseDriver.php::getSequenceTable(169)
 2. ClassMetadataFactory.php::loadMetadataForClass(284)
 3. ClassMetadataFactory.php::loadMetadata(177)
 4. ClassMetadataFactory.php::getMetadataFor(124)
 5. Import.php::getAllMetadata(188)
 6. Command.php::execute(187)
 7. Application.php::run(194)
 8. Application.php::doRun(118)
 9. doctrine.php::run(99)
 10. doctrine::include(4)
==================================================


33

Lạ mà không ai đăng theo cách này:

debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);

Điều này thực sự in backtrace mà không có rác - chỉ là phương thức được gọi và ở đâu.


2
Thật vậy, thực sự tương đương với giải pháp bỏ phiếu chính, và ngắn hơn. Cảm ơn
brunetton

9

Nếu bạn muốn theo dõi ngăn xếp trông rất giống với cách định dạng php theo dõi ngăn xếp ngoại lệ hơn là sử dụng chức năng này, tôi đã viết:

function debug_backtrace_string() {
    $stack = '';
    $i = 1;
    $trace = debug_backtrace();
    unset($trace[0]); //Remove call to this function from stack trace
    foreach($trace as $node) {
        $stack .= "#$i ".$node['file'] ."(" .$node['line']."): "; 
        if(isset($node['class'])) {
            $stack .= $node['class'] . "->"; 
        }
        $stack .= $node['function'] . "()" . PHP_EOL;
        $i++;
    }
    return $stack;
} 

Điều này sẽ trả về một dấu vết ngăn xếp được định dạng như thế này:

#1 C:\Inetpub\sitename.com\modules\sponsors\class.php(306): filePathCombine()
#2 C:\Inetpub\sitename.com\modules\sponsors\class.php(294): Process->_deleteImageFile()
#3 C:\Inetpub\sitename.com\VPanel\modules\sponsors\class.php(70): Process->_deleteImage()
#4 C:\Inetpub\sitename.com\modules\sponsors\process.php(24): Process->_delete() 

2
hoặc chỉ$e = new Exception; echo $e->getTraceAsString();
Brad Kent

Brad, giải pháp đó không xóa mục cuối cùng khỏi dấu vết ngăn xếp để bạn không hiển thị mục theo dõi do Ngoại lệ mới gây ra
TroySteven

8
var_dump(debug_backtrace());

Điều đó có làm những gì bạn muốn?



4

phptrace là một công cụ tuyệt vời để in ngăn xếp PHP bất cứ lúc nào bạn muốn mà không cần cài đặt bất kỳ tiện ích mở rộng nào.

Có hai chức năng chính của phptrace: thứ nhất, in ngăn xếp cuộc gọi của PHP mà không cần cài đặt bất cứ thứ gì, thứ hai, theo dõi các luồng thực thi php cần cài đặt phần mở rộng mà nó cung cấp.

như sau:

$ ./phptrace -p 3130 -s             # phptrace -p <PID> -s
phptrace 0.2.0 release candidate, published by infra webcore team
process id = 3130
script_filename = /home/xxx/opt/nginx/webapp/block.php
[0x7f27b9a99dc8]  sleep /home/xxx/opt/nginx/webapp/block.php:6
[0x7f27b9a99d08]  say /home/xxx/opt/nginx/webapp/block.php:3
[0x7f27b9a99c50]  run /home/xxx/opt/nginx/webapp/block.php:10 

Có phiên bản Windows không?
johnny

Tôi thích địa chỉ bộ nhớ được hiển thị ở đây .. Điều này có thể hữu ích
Tyler Miles

3

Sử dụng debug_backtraceđể có được một thông tin về các chức năng và phương thức đã được gọi và các tệp đã được đưa vào dẫn đến điểm debug_backtraceđược gọi.





1

Giải pháp của Walltearer là tuyệt vời, đặc biệt nếu được đặt trong thẻ 'pre':

<pre>
<?php debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); ?>
</pre>

- trong đó đặt ra các cuộc gọi trên các dòng riêng biệt, được đánh số gọn gàng


0

Tôi đã điều chỉnh câu trả lời của Don Briggs ở trên để sử dụng ghi nhật ký lỗi nội bộ thay vì in công khai, đây có thể là mối quan tâm lớn của bạn khi làm việc trên máy chủ trực tiếp. Ngoài ra, đã thêm một vài sửa đổi như tùy chọn để bao gồm đường dẫn tệp đầy đủ thay vì tên cơ bản (bởi vì, có thể có các tệp có cùng tên trong các đường dẫn khác nhau) và (đối với những người yêu cầu) một đầu ra ngăn xếp nút hoàn chỉnh:

class debugUtils {
    public static function callStack($stacktrace) {
        error_log(str_repeat("=", 100));
        $i = 1;
        foreach($stacktrace as $node) {
            // uncomment next line to debug entire node stack
            // error_log(print_r($node, true));
            error_log( $i . '.' . ' file: ' .$node['file'] . ' | ' . 'function: ' . $node['function'] . '(' . ' line: ' . $node['line'] . ')' );
            $i++;
        }
        error_log(str_repeat("=", 100));
    } 
}

// call debug stack
debugUtils::callStack(debug_backtrace());
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.