Assertions, protection against yourself
When I write new code (especially objects) I tend to build in extra security measures to protect the code against myself or other developers. Please note that I do not mean users but only the people who use the code. To illustrate this we will look at the following example:
1 2 3 4 | function calculate($number1, $number2) { return $number1 + $number2; } |
Of course this example is very simple, I also hope you never create a function for such a basic calculation. Nevertheless it will be useful as an example. If we put our function to the test we can see some problems:
5 6 7 8 | echo calculate(1, 2) . "\n"; echo calculate(1, 'a') . "\n"; echo calculate('a', 'b') . "\n"; echo calculate(new ArrayObject, new ArrayObject) . "\n"; |
Normally on a live server (with error reporting off) the output will be: 3, 1, 0 and 2. The first calculation is valid and just prints what we expected. The other calculations contain other characters than numbers so the outcome is a bit odd. Only the last calculation (when showing notices) will trigger a notice telling you that ArrayObject cannot be converted to a int. Of course we shouldn’t use non-numeric values with this function but during development we could made this kind of mistake.
So how do we fix this? We need a way to tell us that we did something wrong. The most common way is to add some more code that checks our preconditions ($number1 and $number2 must be numeric). You could do this like this:
1 2 3 4 5 6 7 8 9 | function calculate($number1, $number2) { if(!is_numeric($number1) || !is_numeric($number2)) { echo '$number1 and $number2 must be numeric!'; return 0; } return $number1 + $number2; } |
This function will show a nice error message when you used wrong values. Using this method will make debugging easier because your code will tell you what went wrong. However why should we add five extra lines to our (one-line!) function? If we just remember the usage of this function we could also make sure we never use the wrong values as parameters. But then, if we forgot the usage we could spend our valuable developing time debugging why calculate(’a', ‘b’); went wrong.
So we have to find a good balance between less code (read less writing) and good usability. And this is the point assertions are useful. Assertions are pretty easy to use and you basically only have to know one function: assert(mixed $assertion);. As an parameter you use the assertion (or condition) you want to check. An example:
$number = 'abc'; assert('is_numeric($number)');
When executing this code (through command line) we see the following result:
> php -r "$number = 'abc'; assert('is_numeric($number)');" Warning: assert(): Assertion "is_numeric($number)" failed in Command line code on line 1
Our assertion failed! And that is precisely what we wanted. Using this method we can easily check our preconditions on functions. The assertion inside the function will be checked and it will show an error when it returns false. So to improve our calculate() function we could do this:
1 2 3 4 5 6 | function calculate($number1, $number2) { assert('is_numeric($number1) || is_numeric($number2)'); return $number1 + $number2; } |
Now we rewrote our check method in just one line. But there is more! We can also tweak the working of the assert function through assert_options(). There are five options you can change with this function but the most useful option (in my opinion) is ASSERT_BAIL. When enabled this option will make assertions terminate your application when failed. I find this very useful for testing. To enable ASSERT_BAIL just add the following line before your assertions:
assert_options(ASSERT_BAIL, true);
The other options and what they do can be found at the PHP documentation page.
So far we have seen that assertions can be really useful yet should assertions be used for every check? In my opinion you should only use assertions to check parameters that are not user dependent and that can only be invalid during development. Assertions are a way to help you develop and debug your application, not short cuts for validating user input. Quoting from PHP.net:
“Assertions should be used as a debugging feature only. You may use them for sanity-checks that test for conditions that should always be TRUE and that indicate some programming errors if not or to check for the presence of certain features like extension functions or certain system limits and features.
Assertions should not be used for normal runtime operations like input parameter checks. As a rule of thumb your code should always be able to work correctly if assertion checking is not activated.”
Hopefully you now understand the basic idea of assertions. They are great development tools and can even be disabled for production.
Tags: assert, assertions, assert_options, debug, debugging, Development, PHP, validating
This entry was posted on Tuesday, November 24th, 2009 at 20:02 and is filed under Development, PHP. You can follow any comments to this entry through the RSS 2.0 feed. You can leave a comment, or trackback from your own site.