293

I am aware of function debug_backtrace, but I am looking for some ready to use implementation of function like GetCallingMethodName()? It would be perfect if it gave method's class too (if it is indeed a method).

ZygD
  • 22,092
  • 39
  • 79
  • 102
Dawid Ohia
  • 16,129
  • 24
  • 81
  • 95
  • 3
    Ah, yet *another* example where a question or bug report with the superior answer or report is marked as a duplicate of an earlier though inferior posting. I'll have to fix that problem in the industry too. – John May 20 '18 at 00:01

10 Answers10

659

The simplest way is:

echo debug_backtrace()[1]['function'];

As noted in the comments below, this can be further optimized by passing arguments to:

  • omit both the object and args indices
  • limit the number of stack frames returned
echo debug_backtrace(!DEBUG_BACKTRACE_PROVIDE_OBJECT|DEBUG_BACKTRACE_IGNORE_ARGS,2)[1]['function'];
diyism
  • 12,477
  • 5
  • 46
  • 46
  • 36
    Why was this not marked as the correct answer? – MCMXCII Jan 12 '16 at 15:37
  • 1
    Yes, this is the correct answer. I keep coming back and referring to it every time I need it. – Aditya Mittal Apr 07 '16 at 13:29
  • 3
    Just found this. Very useful BUT it's worth noting that there could be a major overhead involved here. I ran `print_r(debug_backtrace())` and it basically crashed my browser with the weight of info it returned. – Mitya Jul 22 '16 at 11:41
  • 14
    since 5.4 you can pass [a second parameter to limit the number of entries](http://br2.php.net/manual/en/function.debug-backtrace.php#refsect1-function.debug-backtrace-parameters). – igorsantos07 Aug 10 '16 at 18:28
  • 5
    If your browser crashed trying to print `debug_backtrace()`, you probably have other, more serious issues. Either you're passing *huge* objects as parameters, or your call-stack is enormously deep, or you're using a pretty dodgy browser! – Bobby Jack Sep 06 '16 at 12:39
  • It supposed to be the first element: debug_backtrace()[0]['function'] – Juljan Nov 30 '17 at 21:41
  • 36
    It's worth optimizing this a little bit: `debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS,2)[1]['function']` – Eugen Mihailescu May 15 '18 at 05:52
  • It's not marked as the correct answer because it has been given **two years** after the former one, but it indeed remains the most relevant. – Obsidian Jun 08 '18 at 13:52
  • I'd upvote twice ! – Diego Favero Oct 27 '19 at 18:15
  • 1
    Note: this only works since PHP 5.4 – rubo77 Apr 15 '20 at 12:08
  • 1
    If all you truly need is the function name, you could further refine the bitmask to `!DEBUG_BACKTRACE_PROVIDE_OBJECT|DEBUG_BACKTRACE_IGNORE_ARGS` – parttimeturtle Jan 12 '21 at 10:03
  • @parttimeturtle: did you mean `^` instead of `!`? – Benoit Duffez Jun 06 '22 at 18:29
  • @BenoitDuffez I did not. `DEBUG_BACKTRACE_PROVIDE_OBJECT` is just an integer constant with a value of `1`, indicating you want the object field populated. Negating that just gives you `0` to indicate the contrary. You don't want to XOR the two constants, you want to negate the first. – parttimeturtle Jun 06 '22 at 18:58
  • `!` is boolean negation, not binary negation. I actually meant `~`, not `^`. Negating `1` does not do anything, you could negate `2` or `1000` it would still give `0`. I think the proper negation would be `~DEBUG_BACKTRACE_PROVIDE_OBJECT`. – Benoit Duffez Jun 14 '22 at 17:47
  • For example, if you want to negate everything but constant `1`, and `2` (implying for example activation of `4`), you would do `~1|2` and not `!1|2`. Test: `$ php -r 'printf("val=%d lneg=%d bneg=%d lcheck=%d ncheck=%d\n", 1|2, !1|2, ~1|2, (!1|2) & 4, (~1|2) & 4);'` prints `val=3 lneg=2 bneg=-2 lcheck=0 ncheck=4`. The 1st check (logical) fails which is not the intent, and the 2nd check (binary) passes which is the intent. – Benoit Duffez Jun 14 '22 at 17:55
  • I'm getting inconsistent behaviour when using tools like ioncode to encrypt your code base. In my case it was not discovering Laravel's BelongsTo relationships in random cases. – jszoja Jan 26 '23 at 11:57
168

The debug_backtrace() function is the only way to know this, if you're lazy it's one more reason you should code the GetCallingMethodName() yourself. Fight the laziness! :D

Alix Axel
  • 151,645
  • 95
  • 393
  • 500
  • 32
    "Fight the laziness! :D" But laziness is a good thing: http://www.codinghorror.com/blog/archives/000237.html :} So if someone has written such a function, I would really appreciate... :} – Dawid Ohia Jan 21 '10 at 16:37
  • 24
    Who needs google while having such a great 'programming answers search engine' as stackoverflow users like You :} http://stackoverflow.com/questions/190421/caller-function-in-php-5/190426#190426 Now seriously, thanks! – Dawid Ohia Jan 21 '10 at 18:44
  • 14
    For Better performance pass these args, `debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)` . – anwerj Nov 15 '16 at 10:59
  • 1
    Thanks. Manual link for reference http://php.net/manual/en/function.debug-backtrace.php – michalzuber Aug 24 '17 at 13:38
  • 3
    It is not about laziness - if the programmer is paid for the solution, it is perfectly valid trying not to reinvent the wheel. – Radium Apr 17 '19 at 14:03
69

As of php 5.4 you can use

        $dbt=debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS,2);
        $caller = isset($dbt[1]['function']) ? $dbt[1]['function'] : null;

This will not waste memory as it ignores arguments and returns only the last 2 backtrace stack entries, and will not generate notices as other answers here.

idragosalex
  • 1,585
  • 1
  • 12
  • 8
38

You can also use the info provided by a php exception, it's an elegant solution:


function GetCallingMethodName(){
    $e = new Exception();
    $trace = $e->getTrace();
    //position 0 would be the line that called this function so we ignore it
    $last_call = $trace[1];
    print_r($last_call);
}

function firstCall($a, $b){
    theCall($a, $b);
}

function theCall($a, $b){
    GetCallingMethodName();
}

firstCall('lucia', 'php');

And you get this... (voilà!)

Array
(
    [file] => /home/lufigueroa/Desktop/test.php
    [line] => 12
    [function] => theCall
    [args] => Array
        (
            [0] => lucia
            [1] => php
        )

)
Lucia
  • 4,657
  • 6
  • 43
  • 57
  • 3
    Interesting approach and I kind of like it but why is it better than using debug_backtrace? – ken Jun 23 '12 at 19:13
  • 2
    Be aware, I did a quick benchmarks and looks like this solution is 2x times slower than the debug_backtrace(). However, we are talking about micro-optimization untill you dont use this method very often in your code – Strae Aug 22 '12 at 09:34
  • 1
    Yes, debug_backtrace is the right solution, but if you tend to forget the name of the functions, create an exception and print its trace might be easier to remember. In my case I use this only for code debugging, I haven't left it on production for any reason. If I wanted to build a debugging/logging system I would use debug_backtrace. – Lucia Jan 26 '15 at 18:59
  • If I call the GetCallingMethodName() function within the "theCall()", then I would expect "firstCall()" as caller function and not the function itself. Setting $last_call = $trace[2]; in GetCallingMethodName() solves the problem. – Selim Acar Aug 05 '15 at 12:44
31

For me debug_backtrace was hitting my memory limit, and I wanted to use this in production to log and email errors as they happen.

Instead I found this solution which works brilliantly!

// Make a new exception at the point you want to trace, and trace it!
$e = new Exception;
var_dump($e->getTraceAsString());

// Outputs the following 
#2 /usr/share/php/PHPUnit/Framework/TestCase.php(626): SeriesHelperTest->setUp()
#3 /usr/share/php/PHPUnit/Framework/TestResult.php(666): PHPUnit_Framework_TestCase->runBare()
#4 /usr/share/php/PHPUnit/Framework/TestCase.php(576): PHPUnit_Framework_TestResult->run(Object(SeriesHelperTest))
#5 /usr/share/php/PHPUnit/Framework/TestSuite.php(757): PHPUnit_Framework_TestCase->run(Object(PHPUnit_Framework_TestResult))
#6 /usr/share/php/PHPUnit/Framework/TestSuite.php(733): PHPUnit_Framework_TestSuite->runTest(Object(SeriesHelperTest), Object(PHPUnit_Framework_TestResult))
#7 /usr/share/php/PHPUnit/TextUI/TestRunner.php(305): PHPUnit_Framework_TestSuite->run(Object(PHPUnit_Framework_TestResult), false, Array, Array, false)
#8 /usr/share/php/PHPUnit/TextUI/Command.php(188): PHPUnit_TextUI_TestRunner->doRun(Object(PHPUnit_Framework_TestSuite), Array)
#9 /usr/share/php/PHPUnit/TextUI/Command.php(129): PHPUnit_TextUI_Command->run(Array, true)
#10 /usr/bin/phpunit(53): PHPUnit_TextUI_Command::main()
#11 {main}"
Anil
  • 21,730
  • 9
  • 73
  • 100
24

My favourite way, in one line!

debug_backtrace()[1]['function'];

You can use it like this:

echo 'The calling function: ' . debug_backtrace()[1]['function'];

Note that this is only compatible with versions of PHP released within the last year. But it's a good idea to keep your PHP up to date anyway for security reasons.

gavanon
  • 1,293
  • 14
  • 15
  • 1
    This method has been provided countless times already, and a problem is that it will only work on PHP 5.4 or higher. – Dave Chen Oct 12 '14 at 00:43
  • 2
    lol thanks @ialarmedalien :D As for compatibility, I'm perhaps too aggressive with updates? I feel people should keep their PHP (reasonably) up to date. It's free, and a security risk to use outdated software. When you're using 2 or 3 year old versions of PHP, you're not just losing out on nice features like this, you're also putting your server at risk. – gavanon Oct 12 '14 at 18:53
  • 3
    @gavanon That comment demonstrates a lack of understanding of how PHP and most popular tools are maintained. PHP 5.3 continued to receive updates for security issues for *years* after the release of PHP 5.4. Just being an an old version of PHP does not mean you are necessarily on an *insecure* PHP. – user229044 Feb 03 '16 at 22:08
  • 1
    @meagar Any version of PHP that doesn't support this method is below version 5.4. Which hasn't been supported or updated since 2015. So yes, it's a security risk to not upgrade. (http://php.net/eol.php) – gavanon Apr 23 '18 at 20:47
15

I just wrote a version of this called "get_caller", I hope it helps. Mine is pretty lazy. You can just run get_caller() from a function, you don't have to specify it like this:

get_caller(__FUNCTION__);

Here's the script in full with a quirky test case:

<?php

/* This function will return the name string of the function that called $function. To return the
    caller of your function, either call get_caller(), or get_caller(__FUNCTION__).
*/
function get_caller($function = NULL, $use_stack = NULL) {
    if ( is_array($use_stack) ) {
        // If a function stack has been provided, used that.
        $stack = $use_stack;
    } else {
        // Otherwise create a fresh one.
        $stack = debug_backtrace();
        echo "\nPrintout of Function Stack: \n\n";
        print_r($stack);
        echo "\n";
    }

    if ($function == NULL) {
        // We need $function to be a function name to retrieve its caller. If it is omitted, then
        // we need to first find what function called get_caller(), and substitute that as the
        // default $function. Remember that invoking get_caller() recursively will add another
        // instance of it to the function stack, so tell get_caller() to use the current stack.
        $function = get_caller(__FUNCTION__, $stack);
    }

    if ( is_string($function) && $function != "" ) {
        // If we are given a function name as a string, go through the function stack and find
        // it's caller.
        for ($i = 0; $i < count($stack); $i++) {
            $curr_function = $stack[$i];
            // Make sure that a caller exists, a function being called within the main script
            // won't have a caller.
            if ( $curr_function["function"] == $function && ($i + 1) < count($stack) ) {
                return $stack[$i + 1]["function"];
            }
        }
    }

    // At this stage, no caller has been found, bummer.
    return "";
}

// TEST CASE

function woman() {
    $caller = get_caller(); // No need for get_caller(__FUNCTION__) here
    if ($caller != "") {
        echo $caller , "() called " , __FUNCTION__ , "(). No surprises there.\n";
    } else {
        echo "no-one called ", __FUNCTION__, "()\n";
    }
}

function man() {
    // Call the woman.
    woman();
}

// Don't keep him waiting
man();

// Try this to see what happens when there is no caller (function called from main script)
//woman();

?>

man() calls woman(), who calls get_caller(). get_caller() doesn't know who called it yet, because the woman() was cautious and didn't tell it, so it recurses to find out. Then it returns who called woman(). And the printout in source-code mode in a browser shows the function stack:

Printout of Function Stack: 

Array
(
    [0] => Array
        (
            [file] => /Users/Aram/Development/Web/php/examples/get_caller.php
            [line] => 46
            [function] => get_caller
            [args] => Array
                (
                )

        )

    [1] => Array
        (
            [file] => /Users/Aram/Development/Web/php/examples/get_caller.php
            [line] => 56
            [function] => woman
            [args] => Array
                (
                )

        )

    [2] => Array
        (
            [file] => /Users/Aram/Development/Web/php/examples/get_caller.php
            [line] => 60
            [function] => man
            [args] => Array
                (
                )

        )

)

man() called woman(). No surprises there.
Aram Kocharyan
  • 20,165
  • 11
  • 81
  • 96
13

I needed something to just list the calling classes/methods (working on a Magento project).

While debug_backtrace provides tons of useful information, the amount of information it spewed out for the Magento installation was overwhelming (over 82,000 lines!) Since I was only concerned with the calling function and class, I worked this little solution up:

$callers = debug_backtrace();
foreach( $callers as $call ) {
    echo "<br>" . $call['class'] . '->' . $call['function'];
}
random_user_name
  • 25,694
  • 7
  • 76
  • 115
6

The simplest way of getting parent function name is:

$caller = next(debug_backtrace())['function'];
kenorb
  • 155,785
  • 88
  • 678
  • 743
  • I like this, but it throws a notice in 7.4. `PHP Notice: Only variables should be passed by reference` - hard coding an array index feels tacky, but I guess if you want a one liner that's what you've got to do. – Full Stack Alien May 25 '21 at 14:52
1

Best answer of that question I've seen is:

list(, $caller) = debug_backtrace(false);

Short and clean

Alex Rashkov
  • 9,833
  • 3
  • 32
  • 58
  • 2
    `debug_backtrace()[1]['function']` doesn't appeal? – AgileTillIDie Jul 11 '13 at 19:47
  • 4
    @AgileTillIDie That would only work in php >= 5.4. – quickshiftin Aug 18 '13 at 15:38
  • list($me, $caller) = debug_backtrace(false); echo $caller['function']; works in PHP >=5.0 and also in PHP 7.x – Frank Jan 05 '18 at 16:27
  • @fyrye `list(, $caller)` is perfectly valid php; the manual states: "`list() constructs can no longer be empty`." That construct is not empty. What is not valid about this answer from 2012--as of php 5.3.6 the method signature is `debug_backtrace(int $options)` and does not accept `false`. – bryonbean Aug 19 '19 at 16:29