Application event tracker (or really simple debugging) for PHP

DISCLAIMER: There’s nothing revolutionary with what you are about to read, should you continue 🙂 This is simply something I did to avoid having to use a debugger where using a debugger wasn’t practical; and also to avoid having to emit “debug output” throughout the application. There are a number of ways to accomplish this, and many people have done it before me. What I describe here works for me. If you break it, you own all the pieces, be it thirteen or four.

The problem, that I had, was to track the progress of an application that did some heavy data processing. During the processing, a number of things could go wrong. It didn’t necessarily have to terminate the application (I don’t like the good old tits up-method of ending a PHP-script, i.e. “die (‘Error’);”), but I needed to track a number of variables and states throughout the execution of the script.

Using “echo ‘The value of x=’.$x” constructs works for really small implementations. It’s a proven “debugging” method and has been used for a long time in the history of computer programming (well, something similar to that construct anyway, considering PHP hasn’t been along for that long).

I have a base class, upon which I base all other classes. If you don’t have one, simply derive the class you want to debug from the code that follows. Also, please note, this method can be extended in a zillion (possibly more) ways. My example doesn’t quite reflect my actual implementation, but it should give you an idea of where this is going.

The class (tested with PHP 5):

[php] class ezPHPdebug {
protected //We do this to avoid non-derived external modification
$__rBuf;//Recording buffer

function __construct ()
{
$this->rBufReset ();//Clear recording buffer
}

function __destruct ()
{ }

function rBufRecord ($s)
{
$this->__rBuf .= $s . “\n”;
}

function rBufReset ()
{
$this->__rBuf = ”;
}

function rBufRead ($forHtml)
{
if ($forHtml)
return (nl2br ($this->__rBuf));
else
return ($this->__rBuf);
}

}//ezPHPdebug
[/php]

Nothing to it, right? Alright, let’s say we create an example class that uses this “debugger”.

[php] class myClass extends ezPHPdebug {
function __construct ()
{
parent::__construct ();
}

function __destruct ()
{
parent::__destruct ();
}

function doSomethingImportant ($x)
{
$this->rBufRecord (‘{doSomethingImportant}’);
$this->rBufRecord (‘x=’.$x);
echo ‘Hello, this is a cool function, it does nothing.’;
echo ‘Oh yes, I forgot, $x is ‘.$x.’
‘;
$this->rBufRecord (‘{/doSomethingImportant}’);
}

function doSomethingElseImportant ($x)
{
$this->rBufRecord (‘{doSomethingElseImportant}’);
$this->rBufRecord (‘x=’.$x);
echo ‘Hello, this is an uncool function, it does something.’;
echo ‘Oh yes, I forgot, $x is ‘.$x.’
‘;
$this->rBufRecord (‘{/doSomethingElseImportant}’);
}

}//myClass
[/php]

This is (obviously) a very simplified way of using the “debugger” class, but it’ll do the job for now.

Now, in the “application” or “main” script, we do something like:

[php] $r = new myClass ();
$r->doSomethingImportant (‘This is a string’);
$r->doSomethingElseImportant (1024);
[/php]

What does this do? Nothing much .. it’ll call the two methods (in myClass), which outputs some data and that’s it. But, what if we wanted to know what happened inside the class (myClass).. well, do this:

[php] $r = new myClass ();
$r->doSomethingImportant (‘This is a string’);
$r->doSomethingElseImportant (1024);
echo ‘TRACKER: ‘.$r->rBufRead (true);
[/php]

This will output the same thing as the first example, plus an additional debug output.

By “recording” entry and exit names, we clearly show that we’re in a function (and that we’re not).

One could add automated timestamping to this, by forcing a timestamp to be inserted each time a line is “recorded”.
Another possible extension is of course to do logging directly to a file or a database; but part of the beauty (IMHO) of the in-memory tracker is that I can output the debug output in one go, and determine when I want to see it.

Leave a Comment

Notify me of followup comments via e-mail. You can also subscribe without commenting.