A simple (and ugly) time-saving line of code

Share and options

Update on Mai, 28 : Added a new code snippet.

Sometimes, when you are trying to debug PHP code, you'll get an ugly WSOD, without any error messages in PHP error log.

When this happens, it's always really difficult to find out why. The lack of message tells you that you you didn't wrote something that bad, but bad enougth for the framework you are working with to partially catch your error without really crashing.

So, how can you resolve this?

1. First, what are you working on?

In many cases, this kind of errors are due to recursive calls, which breaks PHP stack. But, unfortunately, when the recurisvity overlaps more than one function, PHP won't tell you this is an infinite loop.
There are a lot of recursivity breaking algorithm out there, this is not our point today, so where is my infinte loop, and how can I debug it?

2. Second, the Hunch!

Yay, hunch with a capital H! As I said, you have to know more than well the framework you are working on. If you know well all the software layers, you will be able to have THE hunch that will tell you where the infinite loop is going, you wrote the code that bugs, so at least, start by search the framework higher layers you were directly using. Once you found a potential place where in which the current execution flow goes through more than once, let's go for some debugging.

3. Third, the only goal of this post: The Killer Try Statement

When you are debugging infinite loops, you can do all the print("Foo"), print_r("Hey, I am HERE!"), echo("TOGAZOK") you want, PHP in most case won't just display it by crashing before it flushes the output.

So, how can I break the recursivity? The answer: throw an exception!

<?php
 
// This will output in the error log, if not catched.
 
throw new Exception("I am here!");
?>

Magically, in your error log the full stack trace will display.
Because most well coded OOP PHP frameworks will catch exceptions at the lowest level possible (no fatal error should never get back to the user), it may happen that you don't see any output. So let's improve it a bit:
Warning: this is UGLY!

<?php
 
try {
   
// Our exception is catched? Catch it before!
   
throw new Exception("I am here!");
  }
  catch (
Exception $e) {
   
print_r($e->getTraceAsString());
   
// Break the PHP execution.
   
die();
  }
?>

Why the die()? Because if you are inside a recursive loop, you're output won't be flushed and you'll never see your stack trace! This is ugly, but this works everyting, nothing can catch your exception or bypass your die() here.

4. Last, and not least, this can't help

Yes, this can't help, because we are looking for recursive calls, if we use this algorithm, we won't see any inside loops, so here is my ugly but working algorithm, when no other tools can help, count the calls yourself:

<?php
 
static $foo_count = 0;
 
$foo++;
?>

You have then to assume that this is really a recursive call, and arbitrary use your The Killer Try Statement at the Nth call (N is YOUR arbitrary number):

<?php
 
static $foo_count = 0;
 
$foo++;
  if (
$foo == 2) { // Two is my N number, 3 calls is enough to see if there is a recursivity.
   
try {
     
// Our exception is catched? Catch it before!
     
throw new Exception("I am here!");
    }
    catch (
Exception $e) {
     
print_r($e->getTraceAsString());
     
// Break the PHP execution.
     
die();
    }
  }
?>

And there you go, the full stack trace, nicely displayed in your screen instead the WSOD. If the execption don't show up with this algorithm, then you are NOT in a recursive call.

5. Bonus and conclusion

This is really ugly debugging, in all cases, I'd rather use a real debugger. But debbuging PHP is not that easy. You can try xdebug or the Zend Debugger.

Bonus, the compacted one line algorightm (helps sometimes):

<?php
 
static $foo_count = 0; $foo++; if ($foo == 2) { try { throw new Exception("I am here!"); } catch (Exception $e) { print_r($e->getTraceAsString()); die(); } }
?>

Update on Mai, 28 : This code snippet does the same thing without the recursion detection, in other words, it throws an exception at the first pass and display the stack trace, which will allow you to debug the callers stack trace easily.

<?php
 
try { throw new Exception("I am here!"); } catch (Exception $e) { print_r($e->getTraceAsString()); die(); }
?>