A coworker has added the assert command a few times within our libraries in places where I would have used an if statement and thrown an exception. (I had never even heard of assert before this.) Here is an example of how he used it:
assert('isset($this->records); /* Records must be set before this is called. */');
I would have done:
if (!isset($this->records)) {
throw new Exception('Records must be set before this is called');
}
From reading the PHP docs on assert, it looks like it's recommended that you make sure assert is active and add a handler before using assert. I can't find a place where he's done this.
So, my question is, is using assert a good idea given the above and should I be using it more often instead of if's and exceptions?
Another note, we are planning to use these libraries on a variety of projects and servers, including projects that we may not even be part of (the libraries are open source). Does this make any difference in using assert?
An important note concerning assert in PHP earlier than 7. Unlike other languages with an assert construct, PHP doesn't throw assert statements out entirely - it treats it as a function (do a debug_backtrace() in a function called by an assertion). Turning asserts off seems to just hotwire the function into doing nothing in the engine. Note that PHP 7 can be made to emulate this behavior by setting zend.assertions to 0 instead of the more normal values of 1 (on) or -1 (off).
The problem arises in that assert will take any argument - but if the argument is not a string then assert gets the results of the expression whether assert is on or off. You can verify this with the following code block.
Given the intent of assert this is a bug, and a long standing one since it's been in the language since assert was introduced back in PHP 4.
Strings passed to assert are eval'ed, with all the performance implications and hazards that come with that, but it is the only way to get assert statements to work the way they should in PHP (This behavior deprecated in PHP 7.2).
EDIT: Changed above to note changes in PHP 7 and 7.2
Assert is not a substitute for normal flow control like
if
or exceptions, because it is only meant to be used for debugging during development.Assert should only be used in development as it is useful for debugging. So if you want you can use them for developing your website, but you should use exceptions for a live website.
You coworker is really attempting to apply Design-by-Contract (TM) from the Eiffel language and based on the book: Object Oriented Software Construction, 2nd Edition.
The assertion as he used it would be the {P}-part of the Hoare Logic or Hoare Triple: {P} C {Q}, where the {P} is the precondition assert(ion)s and {Q} are the post-condition assert(ion)s.
I would take critical note of advice given about about the assert feature in PHP having bugs. You don't want to use buggy code. What you really want are the makers of PHP to fix the bug in the assert. Until they do, you can use the assert, but use it mindful of its present buggy state.
Moreover, if the assert feature is buggy, then I suggest you do not use it in production code. Nevertheless, I do recommend that you use it in development and testing code where appropriate.
Finally—if you do a study of Design-by-Contract, you will find that there are consequences to using boolean assertions in light of object oriented classical inheritance—that is—you must must never weaken a precondition, nor weaken a post-condition. Doing so could be dangerous to your polymorphic descendent objects interacting with each other. Until you understand what that means—I'd leave it alone!
Moreover—I highly recommend that the makers of PHP do a comprehensive study of Design-by-Contract and attempt to put it into PHP ASAP! Then all of us can benefit from having a DbC-aware compiler/interpreter, which would handle the issues noted in the answers (above):
NOTE: Even your use of an if-statement as a substitute for the assert (precondition) will suffer dire consequences if used to strengthen a precondition or weaken a post-condition. To understand what that means, you will need to study Design-by-Contract to know! :-)
Happy studying and learning.
No, your co-worker shouldn't be using it as a general purpose error handler. According to the manual:
If you are familiar with automated test suites, the "assert" verb is generally used to verify the output of some method or function. For example:
Your co-worker shouldn't be using it as a general purpose error handler and in this case as an input check. It looks like it's possible for the records field to not be set by some user of your library.
It wholly depends on your development strategy. Most developers are unaware of
assert()
and use downstream unit testing. But proactive and built-in testing schemes can sometimes be advantageous.assert is useful, because it can be enabled and disabled. It doesn't drain performance if no such assertion handler is defined. Your collegue doesn't have one, and you should devise some code which temporary enables it in the development environment (if E_NOTICE/E_WARNINGs are on, so should be the assertion handler). I use it occasionally where my code can't stomach mixed variable types - I don't normally engage in strict typing in a weakly typed PHP, but there random use cases:
Which for example would compensate for the lack of type specifiers
string $a, array $b
. PHP5.4 will support them, but not check.