On 07/10/2014 21:07, Levi Morrison wrote:
I would also argue that
you should never, in any language, catch a NPE. The only time you
should catch an NPE is if you are catching all exceptions, such as in
a FastCGI daemon that will cleanly shutdown afterwards.
If you're not allowed to catch it, why make it an exception? Benefits such as
unwinding finally blocks and destructors, and collecting backtraces, are
secondary effects, not really fundamental to exceptions.
This is not a new idea; a very quick search turned up the CERT Oracle
Coding Standard for Java:
"Programs must not catch java.lang.NullPointerException. A
NullPointerException exception thrown at runtime indicates the
existence of an underlying null pointer dereference that must be fixed
in the application code[...] Handling the underlying null pointer
dereference by catching the NullPointerException rather than fixing
the underlying problem is inappropriate for several reasons."
I'll let you read the standard for the justification.
Assuming you mean this (you forgot the link, so I searched the quote):
https://www.securecoding.cert.org/confluence/display/java/ERR08-J.+Do+not+catch+NullPointerException+or+any+of+its+ancestors
They give 3 reasons:
1) Performance overhead.
I have no idea whether this is true for PHP's implementation of
Exceptions, or for the scenario which I came up with earlier.
2) Inability to know which part of the try{} block initiated the error.
This is a fair point, although why it is more true of these exceptions
than any other, I'm not sure.
3) "programs rarely remain in an expected and usable state after a
|NullPointerException| has been thrown"
As mentioned earlier, PHP is not Java, and the closest to a "Null
Pointer" is actually "variable which you thought was going to be an
object but turned out to be a scalar or array". The situations that lead
to the exception are vastly different, so the chances of recoverability
aren't really generalisable from one to the other.
To clarify, this is the kind of code I was thinking of:
$result = DataSource::newInstance()
->select('foo')
->from('bar')
->with('baz') // WHAT IF THIS RETURNS FALSE?
->using('id')
->where('foo_name', $name)
->and('active', true)
->fetchArray();
There are two ways I know of for dealing with an error midway through a
chain like that:
1) Return a "Null Object", or an object which has been put into an error
state, so that all following calls are executed, but do nothing.
2) Throw an exception, so that the chain finishes early, and the calling
code knows an error has occurred.
If the library author has done neither of these, you will be faced with
a "call to a member-function on a non-object" error. Your only recourse
if you cannot / are unwilling to fix the library is to remove the
elegance of the fluent interface and check an intermediate variable with
is_object() or instanceOf on every line.
If that was an exception, then you, as the library consumer, could catch
it, just like you would catch a custom exception thrown by a more
conscientious library author.
The point is that a few applications (and I mean a*very* few) need to
be able to handle these kinds of failures; for example a web server
shouldn't crash because the application throws a NullPointerException;
rather the worker dies and the client will be sent a 500 error and the
web server continues to run normally.
Just to clarify, are you broadly in favour of Engine Exceptions, or
against the whole idea? Because this sounds like a call for something
completely separated from the userland notion of "Exception", and indeed
something that would rarely even be written in PHP rather than C in an
extension.
Regards,
--
Rowan Collins
[IMSoP]