php: determine where function was called from

PhpFunction Calls

Php Problem Overview


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

Php Solutions


Solution 1 - Php

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
                )

        )

)

Solution 2 - Php

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()...
    }
}

Solution 3 - Php

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

Solution 4 - Php

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!';

Solution 5 - Php

Solution 6 - Php

Try below code.

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

Solution 7 - Php

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).

Solution 8 - Php

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionpol_bView Question on Stackoverflow
Solution 1 - PhpromacView Answer on Stackoverflow
Solution 2 - PhpBoltClockView Answer on Stackoverflow
Solution 3 - PhpMariusz CharczukView Answer on Stackoverflow
Solution 4 - PhpmarverixView Answer on Stackoverflow
Solution 5 - PhpYehonatanView Answer on Stackoverflow
Solution 6 - PhpMakwana KetanView Answer on Stackoverflow
Solution 7 - PhpPhillip WeberView Answer on Stackoverflow
Solution 8 - PhpAlienView Answer on Stackoverflow