Article
Effortless (or Better!) Bug Detection with PHP Assertions
Controlling Assertions
The routine used to control assertions in PHP is assert_options. It takes two arguments, one to specify which option to set, and the other to specify the value of that option to set. The constant to enable assertions is ASSERT_ACTIVE with possible values of 0 or 1. So during development, you'll want to do this somewhere early on
assert_options(ASSERT_ACTIVE, 1);
but in production it should read
assert_options(ASSERT_ACTIVE, 0);
You can also control whether you terminate execution when an assertion fails (ASSERT_BAIL) and whether warnings are issued during assertion evaluation (ASSERT_QUIET_EVAL). Be careful with ASSERT_QUIET_EVAL! If it's turned on and there's a problem executing the assertion you wrote, perhaps because of a syntax error or because you called a function that doesn't exist, PHP won't tell you, and your application may behave strangely or halt when it reaches that assertion. Best let the evaluations make some "noise" by setting it to 0 (the default), unless you have a specific reason for turning it on.
Two other interesting options are ASSERT_WARNING and ASSERT_CALLBACK. These allow you to customize how your application reacts to assertions. By default, an assertion failure generates a warning like we saw earlier. But you may want to take more control over assertion handling by writing your own callback routine and installing it with ASSERT_CALLBACK. If you do so, you may choose to suppress the default warnings with ASSERT_WARNING. Let's look at an example.
Getting Fancy
One potential problem with assertions is that they output a warning directly to the page being processed. This means trouble if you're in a section of code generating headers-you'll get the dreaded "Cannot add header information -- headers already sent" warning. It's also a problem if you're in the middle of rendering a page layout, calculating values to display in a form, or performing similar UI-intensive tasks.
There's a solution in the form of an open-source package called phpAssertUnit. It stays "out of the way" by providing a separate Assertion Reporter window to report on failed assertions. It also provides assertions capabilities for JavaScript as well as PHP.
I encourage you to explore the package, but in this article I'll just show you how to use the Assertion Reporter to view failed PHP assertions. The basic idea is to write a PHP assertion handler that sends results to the Assertion Reporter, and to register the handler as the PHP assertion callback. Comments here explain the details.
<?php
include_once('assert.mod'); // phpAssertUnit PHP code
define('FAILED_PHP_ASSERTION',0); // used to create a
// failed phpAssertUnit
// assertion
assert_options(ASSERT_CALLBACK,
phpAssertUnit_callback); // register the handler
assert_options(ASSERT_WARNING, 1); // set to 0 for no
// on-page warning
assert_options(ASSERT_QUIET_EVAL, 0); // leave off if you can
//
function phpAssertUnit_callback($file, $line, $code) {
//
global $Assert; // from phpAssertUnit
//
// Windows: take care of ':' because it's a trigger
// for assertUnit, and prepare '\' for HTML display
// this should have no effect on filepaths from
// Unix/Linux unless they contain these characters).
//
$f = str_replace(':', '&#'.ord(':').';', $file);
$f = str_replace('\\', '\\\\', $f);
//
// If PHP assertion was called with a Boolean expression,
// $code will be unset or empty
// so just label it 'Boolean expression'.
//
if (!isset($code) || $code == '') {
$code = 'Boolean expression';
}
//
// Prepare the code for HTML display...
//
$c = htmlentities($code);
//
// ...and invoke the phpAssertUnit assertion
//
$Assert->isTrue(FAILED_PHP_ASSERTION,
true,
//always report PHP assertions
"PHP Assertion failed on Line $line, File $f: $c");
}
?>
Include this early in your PHP file (or better yet, make it part of a config.php file that is included on every page), make sure the phpAssertUnit files (assert.mod; reporter.html; reporter.js; reporter.css) are in the right places (per the phpAssertUnit documentation and any configuration you've done), and you'll have informative, unobtrusive assertion reporting in a separate window-integrated with JavaScript assertions, if you so choose.
You can see the assertion browser reporting on the assertions discussed in this article here.