พิมพ์ PHP Call Stack


257

ฉันกำลังมองหาวิธีพิมพ์ call stack ใน PHP

คะแนนโบนัสหากฟังก์ชันฟลัชบัฟเฟอร์ IO



12
... แต่คำตอบเหล่านี้ดีกว่า
Ben

คำตอบ:


123

ถ้าคุณต้องการสร้างการติดตามย้อนหลังคุณกำลังมองหาและdebug_backtrace / หรือdebug_print_backtrace


ยกตัวอย่างเช่นตัวแรกจะให้อาเรย์แบบนี้กับคุณ(อ้างอิงจากคู่มือ) :

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


เห็นได้ชัดว่าพวกเขาจะไม่ล้างบัฟเฟอร์ I / O, แต่คุณสามารถทำสิ่งที่ตัวเองมีและflush / หรือob_flush

(ดูหน้าคู่มือของหน้าแรกเพื่อหาสาเหตุที่ "และ / หรือ" ;-))


7
สิ่งนี้ทำให้ php ของฉันหมดหน่วยความจำ ฉันแนะนำโซลูชันของ Tobiasz
peedee

หากคุณพบว่ามันยากที่จะอ่าน / ทำความเข้าใจฉันยังแนะนำวิธีแก้ปัญหาของ Tobiasz ด้วย
ViliusL

1
@peedee สิ่งที่ต้องทำคือการระบุหนึ่งในDEBUG_BACKTRACE_IGNORE_ARGSพารามิเตอร์ทางเลือก ที่ทำให้พวกเขาใช้งานได้เทียบเท่ากับ(new \Exception())->getTraceAsString()

565

อ่านง่ายกว่า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
หืมนี่มันดีกว่านี้ทำไมพวกเขาไม่สามารถสร้างเอาท์พุทเริ่มต้นสำหรับ debug_print_backtrace () ได้? สามารถเพิ่มพารามิเตอร์บูลีน "returnTrace" สำหรับผู้ที่ต้องการมันในตัวแปรไม่ได้สะท้อนและมันจะสมบูรณ์แบบ!
jurchiks

1
ฉันไม่รู้กี่เดือนที่ฉันพยายามคิดว่าจะทำอย่างไรไม่เคยคิดเลยว่ามันจะใช้ได้
WojonsTech

วิธีแก้ปัญหานี้ยังใช้หน่วยความจำน้อยกว่าการจับเอาท์พุทของ debug_backtrace () เป็นอาร์เรย์แล้วพิมพ์โดยใช้ print_r () ซึ่งเป็นสิ่งที่ฉันทำไปจนกระทั่งเห็นสิ่งนี้!
ปีเตอร์

5
ฉันกำลังมองหาวิธี จำกัดdebug_backtraceให้คืนระดับแรกใน stacktrace เท่านั้น - วิธีนี้ใช้ได้ผลกับฉัน ขอบคุณ!
ankr

3
@Andrew print_rจะเก็บข้อความทั้งหมดไว้
mopo922

41

เพื่อบันทึกการติดตาม

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

ขอบคุณ @Tobiasz


35

Backtrace ทิ้งขยะจำนวนมากที่คุณไม่ต้องการ ใช้เวลานานมากอ่านยาก สิ่งที่คุณมักจะต้องการคือ "สิ่งที่เรียกว่าอะไรจากที่ไหน" นี่คือวิธีแก้ปัญหาฟังก์ชั่นแบบคงที่ง่าย ฉันมักจะใส่ไว้ในคลาสที่เรียกว่า 'debug' ซึ่งมีฟังก์ชั่นยูทิลิตีการดีบักทั้งหมดของฉัน

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

คุณเรียกว่าแบบนี้:

debugUtils::callStack(debug_backtrace());

และมันให้ผลลัพธ์เช่นนี้

==================================================
 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

แปลกที่ไม่มีใครโพสต์ด้วยวิธีนี้:

debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);

นี่จะพิมพ์ backtrace โดยไม่ต้องทิ้งขยะ - เพียงวิธีการที่เรียกว่าและที่ไหน


2
ที่จริงแล้วเทียบเท่ากับวิธีแก้ปัญหาหลักที่โหวตแล้วและสั้นกว่า ขอบคุณ
brunetton

9

หากคุณต้องการ stack trace ซึ่งมีลักษณะคล้ายกับวิธีการจัดรูปแบบ php การติดตาม stack stack ยกเว้นการใช้ฟังก์ชั่นนี้ฉันได้เขียนไว้:

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

สิ่งนี้จะส่งคืนการติดตามสแต็กที่จัดรูปแบบดังนี้:

#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
หรือเพียงแค่$e = new Exception; echo $e->getTraceAsString();
Brad Kent

Brad โซลูชันนั้นไม่ได้ลบรายการสุดท้ายออกจากการติดตามสแต็กดังนั้นคุณจะไม่แสดงรายการการติดตามที่เกิดจากข้อยกเว้นใหม่
TroySteven



4

phptraceเป็นเครื่องมือที่ยอดเยี่ยมในการพิมพ์ PHP สแต็คเมื่อใดก็ตามที่คุณต้องการโดยไม่ต้องติดตั้งส่วนขยายใด ๆ

มีหน้าที่หลักสองประการของ phptrace: อันดับแรก print call stack ของ PHP ซึ่งไม่จำเป็นต้องติดตั้งอะไรประการที่สองติดตามการดำเนินการของ php ซึ่งจำเป็นต้องติดตั้งส่วนขยายที่จัดหา

ดังต่อไปนี้:

$ ./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 

มีรุ่นของ Windows หรือไม่
johnny

ฉันชอบที่อยู่หน่วยความจำจะแสดงที่นี่ .. นี่จะเป็นประโยชน์
Tyler Miles

3

ใช้debug_backtraceเพื่อรับ backtrace ว่ามีการเรียกใช้ฟังก์ชันและวิธีการใดบ้างและมีไฟล์ใดบ้างที่รวมอยู่ซึ่งนำไปสู่จุดที่debug_backtraceถูกเรียก





1

โซลูชันของ Walltearer นั้นยอดเยี่ยมโดยเฉพาะถ้าอยู่ในแท็ก 'pre':

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

- ซึ่งกำหนดการโทรออกเป็นสายแยกกันโดยกำหนดหมายเลขไว้อย่างเรียบร้อย


0

ฉันได้ปรับคำตอบของ Don Briggs ด้านบนให้ใช้การบันทึกข้อผิดพลาดภายในแทนการพิมพ์สาธารณะซึ่งอาจเป็นปัญหาใหญ่ของคุณเมื่อทำงานกับเซิร์ฟเวอร์ที่ใช้งานจริง นอกจากนี้ยังเพิ่มการแก้ไขเพิ่มเติมอีกสองสามอย่างเช่นตัวเลือกในการรวมเส้นทางไฟล์แบบเต็มแทนที่จะเป็นชื่อพื้นฐาน (เพราะอาจมีไฟล์ที่มีชื่อเหมือนกันในเส้นทางที่ต่างกัน) และสำหรับผู้ที่ต้องการมันด้วย:

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());
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.