Exceptions

Table of Contents

PHP has an exception model similar to that of other programming
languages. An exception can be thrown, and caught ("catched") within
PHP. Code may be surrounded in a try block, to facilitate the catching
of potential exceptions. Each try must have at least one corresponding
catch or finally block.

The thrown object must be an instance of the
Exception class or a subclass of
Exception. Trying to throw an object that is not
will result in a PHP Fatal Error.

catch

Multiple catch blocks can be used to catch different classes of
exceptions. Normal execution (when no exception is thrown within the try
block) will continue after that last catch block defined in sequence.
Exceptions can be thrown (or re-thrown) within a catch block.

When an exception is thrown, code following the statement will not be
executed, and PHP will attempt to find the first matching catch block.
If an exception is not caught, a PHP Fatal Error will be issued with an
"Uncaught Exception ..." message, unless a handler has
been defined with set_exception_handler().

In PHP 7.1 and later, a catch block may specify multiple exceptions
using the pipe (|) character. This is useful for when
different exceptions from different class hierarchies are handled the
same.

finally

In PHP 5.5 and later, a finally block may also be specified after or
instead of catch blocks. Code within the finally block will always be
executed after the try and catch blocks, regardless of whether an
exception has been thrown, and before normal execution resumes.

If a TRY has a FINALLY, a RETURN either in the TRY or a CATCH won't terminate the script. Code in the same block after the RETURN will not be executed, and the RETURN itself will be "copied" to the bottom of the FINALLY block to be executed.

a RETURN in the FINALLY block will override value(s) returned from the TRY or a CATCH block.

If you intend on creating a lot of custom exceptions, you may find this code useful. I've created an interface and an abstract exception class that ensures that all parts of the built-in Exception class are preserved in child classes. It also properly pushes all information back to the parent constructor ensuring that nothing is lost. This allows you to quickly create new exceptions on the fly. It also overrides the default __toString method with a more thorough one.

Using a return statement inside a finally block will override any other return statement or thrown exception from the try block and all defined catch blocks. Code execution in the parent stack will continue as if the exception was never thrown.

Frankly this is a good design decision because it means I can optionally dismiss all thrown exceptions from 1 or more catch blocks in one place, without having to nest my whole try block inside an additional (and otherwise needless) try/catch block.

This is the same behavior as Java, whereas C# throws a compile time error when a return statement exists inside a finally block. So I figured it was worth pointing out to PHP devs who may not have any exposure to finally blocks or how other languages do it.

Sometimes you want a single catch() to catch multiple types of Exception. In a language like Python, you can specify multiple types in a catch(), but in PHP you can only specify one. This can be annoying when you want handle many different Exceptions with the same catch() block.

However, you can replicate the functionality somewhat, because catch(<classname> $var) will match the given <classname> *or any of it's sub-classes*.

If you are using a namespace, you must indicate the global namespace when using Exceptions.<?phpnamespace alpha;function foo(){ throw new \Exception("Something is wrong!");// throw new Exception(""); will fail}

‘Normal execution (when no exception is thrown within the try block, *or when a catch matching the thrown exception’s class is not present*) will continue after that last catch block defined in sequence.’

‘If an exception is not caught, a PHP Fatal Error will be issued with an “Uncaught Exception …” message, unless a handler has been defined with set_exception_handler().’

These two sentences seem a bit contradicting about what happens ‘when a catch matching the thrown exception’s class is not present’ (and the second sentence is actually correct).

There's some inconsistent behaviour associated with PHP 5.5.3's finally and return statements. If a method returns a variable in a try block (e.g. return $foo;), and finally modifies that variable, the /modified/ value is returned. However, if the try block has a return that has to be evaluated in-line (e.g. return $foo+0;), finally's changes to $foo will /not/ affect the return value.

It looks like it's trying to be efficient by not allocating additional memory for the return value when it thinks it doesn't have to, but the spec is that finally is run after try is completed execution, and that includes the evaluation of the return expression.

One could argue (weakly) that the first method should be the correct result, but at least the two methods should be consistent.

Further to dexen at google dot me dot up with "use destructors to perform a cleanup in case of exception". The fact that PHP5 has destructors, exception handling, and predictable garbage collection (if there's a single reference in scope and the scope is left then the destructor is called immediately) allows for the use of the RAII idiom.

Remember that Exceptions are also objects and can be handled as such; they can be constructed in and returned as values from functions, passed as arguments to other functions, and examined before being thrown. You don't have to throw it as soon as you have constructed it (the stack trace will of course reflect the moment the Exception was constructed, not the moment it was thrown).

You might, for example, want to collect additional information to include in YourException but you don't want to clutter up the YourException class or the code containing the "throw" statement by collecting the information there. Or you might want to do something (such as logging) with each Exception that is thrown from a certain region (catch it, pass it to the logging function, then rethrow it).

Well, it is allowed syntax, it is bad practice, because once it hits the exception block, finally won't be called(because it exits the scope). Finally was invented to prevent duplicated code after one operation, regardless whether it was successful(for example closing the connection to a server). This way, you don't have any duplicated code. So you don't need to use this structure.

Starting in PHP 7, the classes Exception and Error both implement the Throwable interface. This means, if you want to catch both Error instances and Exception instances, you should catch Throwable objects, like this: