Well, that's a couple of hours I'd really like to have back.
One of the oldest, simplest, most generally effective debugging tools is some form of logging. Writing output to a file, to a database, or to the console gives the developer a window into the workings of code, as it's being executed.
The long-time "gold standard" for such tools has been the Apache Foundation's log4j package, which supports Java. As with many tools (e.g., PHPUnit), a good Java tool was ported to, or reimplemented in, PHP. log4php
is uses the same configuration files and (as much as possible) the same APIs as log4j
. However, as PHP and Java are (significantly) different languages, liberties had to be taken in various places. Add to this the fact that PHP has been undergoing significant change in the last couple of years (moving from version 5.2 to the significantly different 5.3 as we wait for the overdue, even more different, 6.0), and a famous warning comes to mind when attempting to use the tool.
The devil, the saying goes, is in the details, and several details of log4php
are broken in various ways. Of course, not all the breakage gives immediately useful information on how to repair it.
Take, as an example, the helper class method LoggerPatternConverter::spacePad()
, reproduced here:
/** * Fast space padding method. * * @param string $sbuf string buffer * @param integer $length pad length * * @todo reimplement using PHP string functions */ public function spacePad($sbuf, $length) { while($length >= 32) { $sbuf .= $GLOBALS['log4php.LoggerPatternConverter.spaces'][5]; $length -= 32; } for($i = 4; $i >= 0; $i--) { if(($length & (1<<$i)) != 0) { $sbuf .= $GLOBALS['log4php.LoggerPatternConverter.spaces'][$i]; } } // $sbuf = str_pad($sbuf, $length); }
Several serious issues are obvious here, the most egregious of which is acknowledged in the @todo note: "reimplement using PHP string functions." The $GLOBALS
item being referenced is initialized at the top of the source file:
$GLOBALS['log4php.LoggerPatternConverter.spaces'] = array( " ", // 1 space " ", // 2 spaces " ", // 4 spaces " ", // 8 spaces " ", // 16 spaces " " ); // 32 spaces
If you feel yourself wanting to vomit upon and/or punch out some spectacularly clueless coder, you have my sympathies.
The crux of the problem is that the function contains seriously invalid code, at least as of PHP 5.3. Worse, the error messages that are given when the bug is exercised are extremely opaque, and a Google search produces absolutely no useful information.
The key, as usual, is in the stack trace emitted after PHP hits a fatal error.
To make a long story short(er), the global can be completely eliminated (it's no longer legal anyway), and the code can be refactored so:
public function spacePad(&$sbuf, $length) { $sbuf .= str_repeat( " ", $length ); }
Of course, this makes the entire method redundant; the built-in str_repeat()
function should be called wherever the method is called.
I'll make that change and submit a patch upstream tomorrow... errr, later today; it's coming up on 1 AM here now.
But at least now I can use log4php
to help me trace through the code I was trying to fix when this whole thing blew up in my face.
At least it's open source under a free license.
No comments:
Post a Comment