Whodunnit

    Harry Fuecks
    Share

    Ever needed to know who called that function or class method resulting in your app going horribly wrong? Try debug_backtrace().

    Dropping this in the function where the problem was found, you get to see the call stack which led up to the function call.

    The call stack is essentially all the currently active functions / methods which have not yet returned to the point where they were called. It’s easiest to see by example.

    Let’s say there’s some code you have where one function calls another which calls another like;


    ";
    }

    function formatName($name) {
    $name = strtolower($name);
    $name = ucfirst($name);
    hello($name);
    }

    function displayMessage($name) {
    formatName($name);
    }
    ?>

    So if displayMessage() is called, it calls formatName() which itself calls hello() (OK this is a dumb example but illustrates the point).

    Now a simple controller for the above functions;


    if ( isset($_GET['name']) ) {
    displayMessage($_GET['name']);
    } else {
    ?>

    Enter your name

    So far so good. But let’s say in a few weeks, you modify the formatName() function and, by mistake, insert a bug;


    function formatName($name) {
    $name = strtolower($name);

    if ($name == 'ted') {
    $name .= ' (nice to see you)';
    } else {
    $name = ucfirst($name);
    }
    hello($name);
    }

    Although Ted is meant to receive an extra friendly message, the first letter of his name is now no longer getting switched to upper case.

    Not realising there’s a problem, a few days later you’re getting angry calls from some customers about the first letter of their name being lower case. Everyone else seems perfectly happy so you’re somewhat perplexed.

    Due to the sheer complexity of the code, finding just where the problem lies is tricky so instead you employ debug_backtrace() in the hello() function, like;


    function hello($name) {
    if ( $name != ucfirst($name) ) {
    // In reality, log to some log file...
    echo "

    ";
             print_r(debug_backtrace());
             echo "

    ";
    }
    echo "Hello $name
    ";
    }

    Now if the first letter of the name is not uppercase, you’ll get to see the call stack. Here’s how it looks;


    Array
    (
    [0] => Array
    (
    [file] => /home/hfuecks/public_html/debug.php
    [line] => 20
    [function] => hello
    [args] => Array
    (
    [0] => ted (nice to see you)
    )

    )

    [1] => Array
    (
    [file] => /home/hfuecks/public_html/debug.php
    [line] => 24
    [function] => formatname
    [args] => Array
    (
    [0] => Ted
    )

    )

    [2] => Array
    (
    [file] => /home/hfuecks/public_html/debug.php
    [line] => 28
    [function] => displaymessage
    [args] => Array
    (
    [0] => Ted
    )

    )

    )

    Each element of the first order array shows you the function called, element 0 being the point where debug_backtrace() was called while those below it being the functions called prior to it (i.e. displayMessage() was called first, so it appears last). Within the second order arrays, you get to see the name of the function called, the file and line number where the function is defined and the arguments is was given.

    In the above trace, you can see that the formatName() function was given the string argument ‘Ted’ but within the hello() function, it’s now in lower case. Suddenly you realise what happened…

    Tools like XDebug provide more powerful debugging facilities but debug_backtrace() can be handy in environments where you don’t have the option of adding your own PHP extensions and can be worthwhile detail to add to your error logs. You need PHP 4.3.x+ to use it BTW.