php: tentukan dari mana fungsi dipanggil

93

apakah ada cara untuk mengetahui, dari mana fungsi dalam PHP dipanggil? contoh:

function epic()
{
  fail();
}

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

Jawaban:

129

Anda bisa menggunakan debug_backtrace().

Contoh:

<?php

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

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

    print_r( $backtrace );
}

epic( 'Hello', 'World' );

Keluaran:

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
                )

        )

)
romac
sumber
5
Pertama kali saya menemukan debug_backtrace()fungsi yang luar biasa. Saya akan menggunakan yang ini!
David Yell
26

Penggunaan 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()...
    }
}
BoltClock
sumber
9
Itu pasti melakukan apa yang Anda inginkan. Namun waspadalah debug_backtrace()adalah panggilan yang mahal. Jangan biasakan menggunakannya untuk menentukan rantai panggilan. Jika Anda ingin "melindungi" fungsi tersebut, lihat OOP dan metode yang dilindungi.
ircmaxell
18

Solusi tercepat dan termudah yang saya temukan

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

)

Saya menguji kecepatan pada laptop 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;

Hasil:

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
Mariusz Charczuk
sumber
Bagi saya DEBUG_BACKTRACE_IGNORE_ARGS sangat berguna, tanpanya akan ada terlalu banyak info.
Arie
15

Jadi jika Anda masih BENAR-BENAR tidak tahu caranya, berikut solusinya:

$backtrace = debug_backtrace();
echo 'Mu name is '.$backtrace[1]['function'].', and I have called him! Muahahah!';
marverix
sumber
1
Jadi Anda bisa menggunakan if ($ backtrace [1] ['function'] == 'epic') {// melakukan beberapa hal; lain lakukan beberapa hal lain; } ?? wow
Buttle Butkus
2
Ya, tapi jangan! Tidak dalam kode aplikasi permanen. Gunakan parameter. debug_backtrace () terlihat seperti operasi yang cukup berat.
Kluny
3

Coba kode di bawah ini.

foreach(debug_backtrace() as $t) {              
   echo $t['file'] . ' line ' . $t['line'] . ' calls ' . $t['function'] . "()<br/>";
}
Makwana Ketan
sumber
Solusi yang baik dan langsung untuk mendapatkan kembali jejak semua file dari mana fungsi tertentu dipanggil.
Pengecualian
3

Jika Anda ingin melacak asal panggilan yang tepat di bagian atas tumpukan, Anda dapat menggunakan kode berikut:

$call_origin = end(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS));

Ini akan mengabaikan fungsi yang dirantai dan hanya mendapatkan info panggilan yang paling relevan (relevan digunakan secara longgar karena bergantung pada apa yang ingin Anda capai).

Phillip Weber
sumber
Terima kasih. yang menghemat banyak waktu bagi saya :)
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");

Semoga bisa membantu seseorang. Jika fungsi sebenarnya berada di luar httpdocs maka itu tidak dapat ditemukan karena server akan diatur untuk tidak mengizinkannya. Hanya mengujinya dalam satu folder juga tetapi metodologi rekursif harus bekerja dalam teori.

Ini seperti versi 0.1 tetapi saya tidak bermaksud melanjutkan pengembangan di atasnya jadi jika seseorang memperbaruinya, silakan memposting ulang.

Asing
sumber
Terlalu banyak pekerjaan: tambahkan ini ke .bashrc function ff() { grep "function $1" $(find ./ -name "*.php") } lalu panggil ff failatau ff epic. lihat: github.com/MaerF0x0/VimSetup/blob/master/bashrc#L122
Mike Graf