PHP debug_backtrace in production code to get information about calling method?
It does feel a little dirty, but as has been well documented, opined, and beaten to death elsewhere, PHP isn't a system designed for elegance.
One highly convoluted reason not to use debug_backtrace for application logic is it's possible some future developer working on PHP could decide "it's just a debug function, performance doesn't matter".
If you're interested in a "better" way of doing this, you could probably use PHP's magic constants to pass in the calling method and class name, and then use a ReflectionMethod object to extract any other information you need.
I put better in quotes because, while this would be cleaner and more correct, the overhead of instantiating a Reflection object may be greater than using the debug_backtrace function.
How to get name of calling function/method in PHP?
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
PHP: how do I know the caller of a function?
Not sure why you would ever care about this, but you can figure that out from the debug_backtrace()
function.
Determine where a function has been called with PHP
From within the function debug_backtrace()
is the only way to determine the caller, unless of course you pass that information as parameter.
Note, that you cannot use default values to do this. E.g.:
function f($param1, $param2, $caller=__FUNCTION__) ...
__FUNCTION__
will be evaluated at parse time, so it'll always have the same value. The function in which scope f
is declared.
Find the class name of the calling function in php
One not so good solution is :
use __METHOD__
or __FUNCTION__
or __CLASS__
.
and pass it as parameter to function being called.
http://codepad.org/AVG0Taq7
<?php
class Zebra{
public static function action($source){
print 'I was called from the '.$source.' class'; // How do I get water here?
}
}
class Water{
public static function drink(){
Zebra::action(__CLASS__);
}
}
Water::drink();
?>
Why is debug_backtrace() not including line number sometimes?
Consider following code:
<?
class BtTest
{
public function getTheItem()
{
var_dump( debug_backtrace( false ) );
$bt = debug_backtrace( false );
return $bt[1];
}
public function __call( $methodName, $methodArgs )
{
return $this->getTheItem();
}
}
$o = new BtTest();
$bti = $o->test();
assert( 'array_key_exists("function", $bti)' );
assert( 'array_key_exists("line", $bti)' );
assert( 'array_key_exists("file", $bti)' );
The execution of above example generates following output:
array(3) {
[0]=>
array(6) {
["file"]=>
string(53) "/somewhere/in/the/filesystem/tests/bt-test-so.php"
["line"]=>
int(13)
["function"]=>
string(10) "getTheItem"
["class"]=>
string(6) "BtTest"
["type"]=>
string(2) "->"
["args"]=>
array(0) {
}
}
[1]=>
array(4) {
["function"]=>
string(6) "__call"
["class"]=>
string(6) "BtTest"
["type"]=>
string(2) "->"
["args"]=>
array(2) {
[0]=>
&string(4) "test"
[1]=>
&array(0) {
}
}
}
[2]=>
array(6) {
["file"]=>
string(53) "/somewhere/in/the/filesystem/tests/bt-test-so.php"
["line"]=>
int(18)
["function"]=>
string(4) "test"
["class"]=>
string(6) "BtTest"
["type"]=>
string(2) "->"
["args"]=>
array(0) {
}
}
}
PHP Warning: assert(): Assertion "array_key_exists("line", $bti)" failed in /somewhere/in/the/filesystem/tests/bt-test-so.php on line 21
PHP Warning: assert(): Assertion "array_key_exists("file", $bti)" failed in /somewhere/in/the/filesystem/tests/bt-test-so.php on line 22
The first backtrace item (index 0) says indirectly (through the line
and file
items) that the getTheItem
method was called from the __call
method.
The second backtrace item (index 1) says that the __call
method was called from somewhere (missing line
and file
items).
The third backtrace item (index 2) says that the test
method was called from the global scope of the script.
The place of the __call
method call is probably in some method resolution code somewhere in the php interpreter code. There are two possibilities of fixing it. Either the second item should refer interpreter's source code file and line or the second and the third backtrace items should be merged into one. I personally would prefer the second solution as the interpreter's internals are not interesting for me (this is how they seem to do it in python's traceback), however I understand that sometimes the first solution provides more explicit trace (especially when it's a callback which is called from the internals).
So or so, it seems that the developer(s) responsible for (or at least maintaining) the code of the debug_backtrace
function doesn't perceive it as a bug or maybe has no easy way to fix it. It would be ok to fill the line
and file
items with some place holder values (e.g. <unknown-file>
and 0
or even nulls) and emphasize it in the documentation. Unless someone will successfully convince them to do it, you just have to handle the special case in your code.
I wrote above just to share my understanding of the strange behaviour of the function. If someone has a willingness to fight for a slightly better world, here are links to some related bug reports:
- #39070 debug_backtrace output when call_user_func or error handler involved
- #24214 debug_backtrace() fails to report
__FILE__
,__LINE__
- #24405 debug_backtrace - missing info
- #38047 "file" and "line" sometimes not set in backtrace from inside error handler
- #44428 "file" and "line" missing in debug_backtrace() output
The oldest report is from 2003, so you shouldn't count on a fast fix :)
Debugging PHP Code with debug_backtrace
I would install XDebug and hook up the remote debugging to your IDE (e.g PhpStorm or Eclipse), that way you will get nice stack dumps on all errors, plus the ability to breakpoint your code and inspect the stack and all object internals at your leisure.
http://xdebug.org/
You can also use it to profile your application call chains without making any code changes (which sounds more like what you are wanting). By using the profiling options, which generate big log files, you can then load these logs into webgrind and visually inspect who's calling what in nice tree structures.
https://code.google.com/p/webgrind/
The Zend tool chain would also provide this kind of deeper debugging functionality out of the box.
Alternatively install an Application Performance Monitoring agent such as App Dynamics or New Relic for similar code-profiling. This is most useful for remote installations (i.e. production) where debugging isn't an option and profiling is expensive.
Print PHP Call Stack
If you want to generate a backtrace, you are looking for debug_backtrace
and/or debug_print_backtrace
.
The first one will, for instance, get you an array like this one (quoting the manual) :
array(2) {
[0]=>
array(4) {
["file"] => string(10) "/tmp/a.php"
["line"] => int(10)
["function"] => string(6) "a_test"
["args"]=>
array(1) {
[0] => &string(6) "friend"
}
}
[1]=>
array(4) {
["file"] => string(10) "/tmp/b.php"
["line"] => int(2)
["args"] =>
array(1) {
[0] => string(10) "/tmp/a.php"
}
["function"] => string(12) "include_once"
}
}
They will apparently not flush the I/O buffer, but you can do that yourself, with flush
and/or ob_flush
.
(see the manual page of the first one to find out why the "and/or" ;-) )
Related Topics
A Better Approach Than Storing MySQL Password in Plain Text in Config File
How to Use Class Methods as Callbacks
Is It Recommended to Store PHP Sessions in Memcache
How to Build Unlimited Level of Menu Through PHP and MySQL
Request Headers Bag Is Missing Authorization Header in Symfony 2
PHP Regular Expression for Strong Password Validation
PHP 5.4 - 'Closure $This Support'
How to Run a PHP Without a Web Server
Convert Jpg/Gif Image to Png in PHP
Wamp/MySQL Errors Not in Correct Language
How to Convert Seconds to Time Format
How to Pass Get Parameters to Laravel from with Get Method
When *Not* to Use Prepared Statements
How to Display Unicode Data with PHP
PHP - How to Build Tree Structure List