Search code examples
phpdebug-backtrace

Why does debug_backtrace() return nothing?


I have PHP code in PHP 7.4

Part of this code is a top level PHP script (/home/path/a.php) which contains a bunch of try catch blocks and contains verious calls to objects and include files.

These try/catch blocks throw on customer errors and runtime errors etc.

In the throw there's an error log including a debug_backtrace() print to the error log.

// some code
use some/path/to/objects; 
$database = new Database();
include "some/file/reference.php";

try {
//   various things including $_SESSION data

    if (empty($_SESSION['b']) || empty($_POST['d'])) {
        if(empty($_SESSION['b'])) {
            error_log("session appears empty. No b");
        }
        if(empty($_POST['d'])) {
            error_log("POST appears empty. No d");
        }
        throw new RuntimeException('Incorrect validation/form details given.');
    }
}
catch (RuntimeException | Exception $ex) {
    error_log("Login Page: ".$_SESSION['message']);
    error_log("debug: ".print_r(debug_backtrace(),true));
}

However, this code runs and collects the errors correctly, but the error log only shows this:

[31-Jul-2023 18:42:17 Europe/London] Some custom feedback message from $_SESSION['message']
[31-Jul-2023 18:42:17 Europe/London] Array
(
)

Why is Debug_backtrace() empty here? I am expecting it to at least show arguments and variables given by the page, or the SESSION data or enviornment data?

I have used this method elsewhere and it (as far as I recall) worked correctly . What am I missing?


Solution

  • debug_backtrace() gives you the call stack that led you to where you are, but you're already in the outermost (ie global) scope, and you haven't made any calls, so there is no call stack.

    print_r(debug_backtrace());
    

    Yields:

    Array
    (
    )
    

    If you put your code in a function, you'll get a call stack with one item:

    function foo()
    {
        print_r(debug_backtrace());
    }
    foo();
    

    Yields:

    Array
    (
        [0] => Array
            (
                [file] => ...
                [line] => 6
                [function] => foo
                [args] => Array
                    (
                    )
    
            )
    
    )
    

    If you want some (minimal) debugging info when you're in the global scope, you could wrap all your code in a closure, and then just immediately invoke that inline:

    (function() {
        // all your code here
        print_r(debug_backtrace());
    })();
    

    Yields:

    Array
    (
        [0] => Array
            (
                [file] => ...
                [line] => 5
                [function] => {closure}
                [args] => Array
                    (
                    )
            )
    )
    

    Regarding session/environment data, it's only going to show you such things if you pass them as arguments:

    foo($_ENV);
    

    Yields:

    Array
    (
        [0] => Array
            (
                [file] => ...
                [line] => 6
                [function] => foo
                [args] => Array
                    (
                        [0] => Array
                            (
                                [TERM] => xterm
                                [PATH] => /usr/bin:/bin
                                [LANG] => C
                                [SHELL] => /bin/sh
                                [MAIL] => /var/mail/nobody
                                [LOGNAME] => nobody
                                [USER] => nobody
                                [HOME] => /tmp
                            )
                    )
            )
    )
    

    If you want to log session/environment variables like this, you're probably just better off dumping them explicitly:

    error_log(print_r($_ENV, true));
    error_log(print_r($_SESSION, true));