php: determine where function was called from
Asked Answered
P

8

103

is there a way to find out, where a function in PHP was called from? example:

function epic()
{
  fail();
}

function fail()
{
  //at this point, how do i know, that epic() has called this function?
}
Purpose answered 2/6, 2010 at 19:9 Comment(0)
R
141

You can use debug_backtrace().

Example:

<?php

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

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

    print_r( $backtrace );
}

epic( 'Hello', 'World' );

Output:

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
                )

        )

)
Retool answered 2/6, 2010 at 19:15 Comment(1)
First time I found debug_backtrace() what a superb function. I'll be using this one!Taking
Q
30

Use 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()...
    }
}
Quaff answered 2/6, 2010 at 19:13 Comment(1)
That definitely does what you want. But beware debug_backtrace() is an expensive call. Don't get in the habit of using it to determine call-chains. If you want to "protect" those functions, check out OOP and protected methods.Dignadignified
H
23

Fastest and simplest solution as I found

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

)

I test the speed on Lenovo laptop: 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;

Results:

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
Heroine answered 16/9, 2016 at 7:54 Comment(1)
For me DEBUG_BACKTRACE_IGNORE_ARGS was very useful, without it there was way too many info.Kalle
M
16

So if you still REALLY don't know how, than here is solution:

$backtrace = debug_backtrace();
echo 'Mu name is '.$backtrace[1]['function'].', and I have called him! Muahahah!';
Moline answered 21/6, 2012 at 8:13 Comment(2)
So you could use if($backtrace[1]['function'] == 'epic') { // do some stuff; else do some other stuff; } ?? wowBangor
Yes, but don't! Not in permanent application code, anyway. Use parameters. debug_backtrace() looks like a pretty heavy operation.Peterkin
F
7

Try below code.

foreach(debug_backtrace() as $t) {              
   echo $t['file'] . ' line ' . $t['line'] . ' calls ' . $t['function'] . "()<br/>";
}
Fraction answered 28/4, 2016 at 11:4 Comment(2)
Good and direct solution to get back trace of all the files from which particular function is called.Jordans
This is the only one that worked for me. Thanks!Induline
F
5

Use the debug_backtrace function: http://php.net/manual/en/function.debug-backtrace.php

Fine answered 2/6, 2010 at 19:12 Comment(0)
S
3

If you want to trace the exact origin of the call at the top of the stack you can use the following code:

$call_origin = end(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS));

This will ignore chained functions and get only the most relevant call info (relevant is used loosely as it depends what your are trying to accomplish).

Sargassum answered 28/12, 2017 at 18:48 Comment(1)
Thank you. that saved a lot of time for me :)Shyster
M
-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");

Hope it helps somebody. If the actual function is outside httpdocs then it can not be found because the server will be setup to not allow it. Only tested it one folder deep too but the recursive methodology should work in theory.

This is like version 0.1 but I don't intend on continuing development on it so if someone updates it feel free to repost it.

Moitoso answered 8/11, 2011 at 14:54 Comment(1)
Too much work: add this to .bashrc function ff() { grep "function $1" $(find ./ -name "*.php") } then call ff fail or ff epic. see: github.com/MaerF0x0/VimSetup/blob/master/bashrc#L122Dome

© 2022 - 2024 — McMap. All rights reserved.