php: กำหนดตำแหน่งที่เรียกใช้ฟังก์ชัน


94

มีวิธีค้นหาว่าฟังก์ชันใน PHP ถูกเรียกมาจากไหน? ตัวอย่าง:

function epic()
{
  fail();
}

function fail()
{
  //at this point, how do i know, that epic() has called this function?
}

คำตอบ:


131

คุณสามารถใช้debug_backtrace().

ตัวอย่าง:

<?php

function epic( $a, $b )
{
    fail( $a . ' ' . $b );
}

function fail( $string )
{
    $backtrace = debug_backtrace();

    print_r( $backtrace );
}

epic( 'Hello', 'World' );

เอาท์พุต:

Array
(
    [0] => Array
        (
            [file] => /Users/romac/Desktop/test.php
            [line] => 5
            [function] => fail
            [args] => Array
                (
                    [0] => Hello World
                )

        )

    [1] => Array
        (
            [file] => /Users/romac/Desktop/test.php
            [line] => 15
            [function] => epic
            [args] => Array
                (
                    [0] => Hello
                    [1] => World
                )

        )

)

5
ครั้งแรกที่ฉันพบdebug_backtrace()ว่าฟังก์ชันที่ยอดเยี่ยม ฉันจะใช้อันนี้!
David Yell

26

ใช้debug_backtrace():

function fail()
{
    $backtrace = debug_backtrace();

    // Here, $backtrace[0] points to fail(), so we'll look in $backtrace[1] instead
    if (isset($backtrace[1]['function']) && $backtrace[1]['function'] == 'epic')
    {
        // Called by epic()...
    }
}

9
แน่นอนว่าสิ่งที่คุณต้องการ แต่ระวังdebug_backtrace()เป็นค่าโทรแพง อย่าติดนิสัยที่จะใช้มันเพื่อกำหนด call-chain หากคุณต้องการ "ปกป้อง" ฟังก์ชันเหล่านั้นโปรดดู OOP และวิธีการป้องกัน
ircmaxell

18

วิธีแก้ปัญหาที่เร็วและง่ายที่สุดเท่าที่ฉันพบ

public function func() { //function whose call file you want to find
    $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
}

$trace: Array
(
    [0] => Array
        (
            [file] => C:\wamp\www\index.php
            [line] => 56
            [function] => func
            [class] => (func Class namespace)
            [type] => ->
        )

)

ฉันทดสอบความเร็วบนแล็ปท็อป Lenovo: Intel Pentiom CPU N3530 2.16GHz, RAM 8GB

global $times;
$start = microtime(true);
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
$times[] = microtime(true) - $start;

ผล:

count($times):  97
min:    2.6941299438477E-5
max:   10.68115234375E-5
avg:    3.3095939872191E-5
median: 3.0517578125E-5
sum:  321.03061676025E-5

the same results with notation without E-5
count($times):  97
min:    0.000026941299438477
max:    0.0001068115234375
avg:    0.000033095939872191
median: 0.000030517578125
sum:    0.0032103061676025

สำหรับฉัน DEBUG_BACKTRACE_IGNORE_ARGS มีประโยชน์มากหากไม่มีข้อมูลมากเกินไป
Arie

15

ดังนั้นหากคุณยังไม่รู้จริง ๆ วิธีแก้ปัญหา:

$backtrace = debug_backtrace();
echo 'Mu name is '.$backtrace[1]['function'].', and I have called him! Muahahah!';

1
คุณสามารถใช้ if ($ backtrace [1] ['function'] == 'epic') {// ทำบางอย่าง; อย่างอื่นทำอย่างอื่น } ?? wow
Buttle Butkus

2
ได้ แต่อย่า! ไม่ได้อยู่ในรหัสแอปพลิเคชันถาวรอยู่ดี ใช้พารามิเตอร์ debug_backtrace () ดูเหมือนจะเป็นการดำเนินการที่ค่อนข้างหนัก
Kluny


3

ลองใช้โค้ดด้านล่าง

foreach(debug_backtrace() as $t) {              
   echo $t['file'] . ' line ' . $t['line'] . ' calls ' . $t['function'] . "()<br/>";
}

ทางออกที่ดีและตรงไปตรงมาเพื่อย้อนกลับไฟล์ทั้งหมดที่เรียกใช้ฟังก์ชันเฉพาะ
ข้อยกเว้น

3

หากคุณต้องการติดตามจุดเริ่มต้นที่แน่นอนของการโทรที่ด้านบนสุดของสแต็กคุณสามารถใช้รหัสต่อไปนี้:

$call_origin = end(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS));

การดำเนินการนี้จะเพิกเฉยต่อฟังก์ชันที่ถูกล่ามโซ่และรับเฉพาะข้อมูลการโทรที่เกี่ยวข้องมากที่สุด (เกี่ยวข้องจะถูกใช้อย่างหลวม ๆ เนื่องจากขึ้นอยู่กับสิ่งที่คุณพยายามทำให้สำเร็จ)


ขอขอบคุณ. ที่ช่วยฉันได้มาก :)
Mohamed hesham

-1
function findFunction($function, $inputDirectory=""){
    //version 0.1
    $docRoot = getenv("DOCUMENT_ROOT");
    $folderArray = null;
    $dirArray = null;

    // open directory
    $directory = opendir($docRoot.$inputDirectory);

    // get each entry
    while($entryName = readdir($directory)) {
        if(is_dir($entryName) && $entryName != "." && $entryName != ".."){
            $folderArray[] = str_replace($inputDirectory, "", $entryName);
        }
        $ext = explode(".", $entryName);
        if(!empty($ext[1])){
            $dirArray[] = $docRoot.$inputDirectory."/".$entryName;
        }
    }

    // close directory
    closedir($directory);
    $found = false;

    if(is_array($dirArray)){
        foreach($dirArray as $current){
            $myFile = file_get_contents($current);
            $myFile = str_replace("<?php", "", $myFile);
            $myFile = str_replace("?>", "", $myFile);
            if(preg_match("/function ".$function."/", $myFile)){
                $found = true;
                $foundLocation = $current;
                break;
            }
        }
    }
    if($found){
        echo $foundLocation;
        exit;
    } else if(is_array($folderArray)){
        foreach($folderArray as $folder){
            if(!isset($return)){
                $return = findFunction($function, $inputDirectory."/".$folder);
            } else if($return == false){
                $return = findFunction($function, $inputDirectory."/".$folder);
            }
        }
    } else {
        return false;
    }
}

findFunction("testFunction", "rootDirectory");

หวังว่ามันจะช่วยใครสักคน หากฟังก์ชันจริงอยู่นอก httpdocs จะไม่พบเนื่องจากเซิร์ฟเวอร์จะถูกตั้งค่าไม่ให้อนุญาต ทดสอบเพียงหนึ่งโฟลเดอร์ที่ลึกเกินไป แต่วิธีการเรียกซ้ำควรทำงานในทางทฤษฎี

นี่เหมือนกับเวอร์ชัน 0.1 แต่ฉันไม่ได้ตั้งใจที่จะพัฒนาต่อไปดังนั้นหากมีคนอัปเดตก็อย่าลังเลที่จะโพสต์ใหม่


ทำงานมากเกินไป: เพิ่มสิ่งนี้ใน. bashrc function ff() { grep "function $1" $(find ./ -name "*.php") } แล้วโทรff failหรือff epic. ดู: github.com/MaerF0x0/VimSetup/blob/master/bashrc#L122
Mike Graf
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.