php: xác định nơi hàm được gọi từ


93

có cách nào để tìm ra một hàm trong PHP được gọi từ đâu không? thí dụ:

function epic()
{
  fail();
}

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

Câu trả lời:


128

Bạn có thể sử dụng debug_backtrace().

Thí dụ:

<?php

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

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

    print_r( $backtrace );
}

epic( 'Hello', 'World' );

Đầu ra:

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
Lần đầu tiên tôi tìm thấy debug_backtrace()một chức năng tuyệt vời. Tôi sẽ sử dụng cái này!
David Yell

26

Sử dụng 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
Điều đó chắc chắn làm những gì bạn muốn. Nhưng hãy cẩn thận debug_backtrace()là một cuộc gọi đắt tiền. Đừng có thói quen sử dụng nó để xác định chuỗi cuộc gọi. Nếu bạn muốn "bảo vệ" các chức năng đó, hãy xem OOP và các phương pháp được bảo vệ.
ircmaxell

18

Giải pháp nhanh nhất và đơn giản nhất như tôi đã tìm thấy

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

)

Mình test tốc độ trên laptop Lenovo: CPU Intel Pentiom N3530 2.16GHz, RAM 8GB

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

Các kết quả:

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

Đối với tôi, DEBUG_BACKTRACE_IGNORE_ARGS rất hữu ích, nếu không có nó thì có quá nhiều thông tin.
Arie

15

Vì vậy, nếu bạn vẫn THỰC SỰ không biết làm thế nào, thì đây là giải pháp:

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

1
Vì vậy, bạn có thể sử dụng if ($ backtrace [1] ['function'] == 'epic') {// làm một số thứ; khác làm một số công cụ khác; } ?? wow
Buttle Butkus,

2
Có, nhưng đừng! Không phải trong mã ứng dụng vĩnh viễn, dù sao. Sử dụng các thông số. debug_backtrace () trông giống như một hoạt động khá nặng.
Kluny


3

Hãy thử mã bên dưới.

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

Giải pháp tốt và trực tiếp để lấy lại dấu vết của tất cả các tệp mà từ đó hàm cụ thể được gọi.
Ngoại lệ

3

Nếu bạn muốn theo dõi nguồn gốc chính xác của cuộc gọi ở đầu ngăn xếp, bạn có thể sử dụng mã sau:

$call_origin = end(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS));

Điều này sẽ bỏ qua các chức năng được xâu chuỗi và chỉ nhận được thông tin cuộc gọi phù hợp nhất (có liên quan được sử dụng một cách lỏng lẻo vì nó phụ thuộc vào những gì bạn đang cố gắng hoàn thành).


Cảm ơn bạn. đã cứu rất nhiều thời gian cho tôi :)
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");

Hy vọng nó sẽ giúp ai đó. Nếu chức năng thực sự nằm ngoài httpdocs thì không thể tìm thấy nó vì máy chủ sẽ được thiết lập để không cho phép nó. Chỉ kiểm tra nó sâu một thư mục nhưng phương pháp đệ quy sẽ hoạt động trên lý thuyết.

Đây giống như phiên bản 0.1 nhưng tôi không có ý định tiếp tục phát triển nó nên nếu ai đó cập nhật, hãy đăng lại nó.


Quá nhiều việc: thêm cái này vào .bashrc function ff() { grep "function $1" $(find ./ -name "*.php") } rồi gọi ff failhoặc ff epic. xem: github.com/MaerF0x0/VimSetup/blob/master/bashrc#L122
Mike Graf
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.