Cetak PHP Call Stack

Jawaban:

123

Jika Anda ingin membuat backtrace, Anda mencari debug_backtracedan / atau debug_print_backtrace.


Misalnya, yang pertama akan memberi Anda array seperti ini (mengutip manual) :

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"
  }
}


Mereka tampaknya tidak akan menyiram buffer I / O, tetapi Anda dapat melakukannya sendiri, dengan flushdan / atau ob_flush.

(lihat halaman manual yang pertama untuk mengetahui mengapa "dan / atau" ;-))

Pascal MARTIN
sumber
7
ini secara teratur membuat php saya kehabisan memori. Saya merekomendasikan solusi Tobiasz.
pipi
Jika Anda merasa sulit untuk membaca / memahami, saya juga merekomendasikan solusi
Tobiasz
1
@eedee yang diperlukan hanyalah menyediakan salah satu DEBUG_BACKTRACE_IGNORE_ARGSparameter opsional ; yang membuat mereka secara fungsional setara dengan(new \Exception())->getTraceAsString()
566

Lebih mudah dibaca daripada 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}"
Tobias Cudnik
sumber
50
Sial, ini jauh lebih baik, mengapa mereka tidak bisa menjadikan ini output default untuk debug_print_backtrace ()? Bisa saja menambahkan parameter boolean "returnTrace" bagi mereka yang menginginkannya dalam variabel, tidak digaungkan, dan itu akan menjadi sempurna!
Jurchiks
1
Saya tidak tahu berapa bulan saya telah mencoba untuk mencari tahu bagaimana melakukan itu tidak pernah berpikir itu akan berhasil
WojonsTech
Solusi ini juga tampaknya mengambil lebih sedikit memori daripada menangkap output dari debug_backtrace () sebagai array dan kemudian mencetaknya menggunakan print_r (), yang merupakan apa yang telah saya lakukan sampai saya melihat ini!
Peter
5
Saya sedang mencari cara untuk membatasi debug_backtraceuntuk hanya mengembalikan level pertama di stacktrace - solusi ini bekerja untuk saya. Terima kasih!
ankr
3
@Andrew print_rakan menyimpan semua pesan.
mopo922
41

Untuk mencatat jejak

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

Terima kasih @Tobiasz

Sydwell
sumber
35

Backtrace membuang banyak sampah yang tidak Anda butuhkan. Butuh waktu sangat lama, sulit dibaca. Yang Anda inginkan adalah "apa yang disebut dari mana?" Berikut ini adalah solusi fungsi statis sederhana. Saya biasanya meletakkannya di kelas yang disebut 'debug', yang berisi semua fungsi utilitas debugging saya.

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++;
        }
    } 
}

Anda menyebutnya seperti ini:

debugUtils::callStack(debug_backtrace());

Dan itu menghasilkan output seperti ini:

==================================================
 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)
==================================================
Don Briggs
sumber
33

Aneh bahwa tidak ada yang diposting dengan cara ini:

debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);

Ini sebenarnya mencetak backtrace tanpa sampah - hanya metode apa yang disebut dan di mana.

AbstractVoid
sumber
2
Memang benar-benar setara dengan solusi pilihan utama, dan lebih pendek. Terima kasih
brunetton
9

Jika Anda ingin jejak stack yang terlihat sangat mirip dengan bagaimana format php jejak stack pengecualian daripada menggunakan fungsi ini saya tulis:

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;
} 

Ini akan mengembalikan jejak jejak yang diformat seperti ini:

#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() 
TroySteven
sumber
2
atau hanya$e = new Exception; echo $e->getTraceAsString();
Brad Kent
Brad, solusi itu tidak menghapus item terakhir dari jejak tumpukan sehingga Anda tidak menampilkan item jejak yang disebabkan oleh Pengecualian baru
TroySteven
8
var_dump(debug_backtrace());

Apakah itu melakukan apa yang Anda inginkan?

inkedmn
sumber
6

Lihat debug_print_backtrace. Saya kira Anda dapat menelepon flushsetelah itu jika Anda mau.

Martin Geisler
sumber
4

phptrace adalah alat yang hebat untuk mencetak tumpukan PHP kapan saja Anda inginkan tanpa menginstal ekstensi apa pun.

Ada dua fungsi utama dari phptrace: pertama, print call stack PHP yang tidak perlu menginstal apa pun, kedua, lacak arus eksekusi php yang perlu menginstal ekstensi yang disediakannya.

sebagai berikut:

$ ./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 
bahasa baru
sumber
Apakah ada versi Windows?
johnny
Saya suka alamat memori yang ditampilkan di sini .. Ini bisa membantu
Tyler Miles
3

Gunakan debug_backtraceuntuk mendapatkan backtrace dari fungsi dan metode apa yang telah dipanggil dan file apa yang dimasukkan yang mengarah ke titik di mana debug_backtracetelah dipanggil.

Gumbo
sumber
1

debug_backtrace()

pix0r
sumber
1

Solusi Walltearer sangat baik, terutama jika disertakan dalam tag 'pra':

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

- yang menetapkan panggilan pada saluran terpisah, bernomor rapi

Geoff Kendall
sumber
0

Saya telah mengadaptasi jawaban Don Briggs di atas untuk menggunakan logging kesalahan internal alih-alih pencetakan publik, yang mungkin menjadi perhatian besar Anda ketika bekerja pada server langsung. Juga, menambahkan beberapa modifikasi seperti opsi untuk memasukkan path file lengkap alih-alih nama dasar (karena, mungkin ada file dengan nama yang sama di jalur yang berbeda), dan juga (bagi mereka yang membutuhkannya) output node stack lengkap:

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());
dev101
sumber