Exceptions
| Throw | |
| Catch by type | |
| finally always runs | |
| Your own exception class |
Throw
Use throw when a function cannot keep its contract.
Throwing stops the current path at once and carries an object with the reason.
Since PHP 8.0 throw is also an expression, so it fits inside
null coalescing and arrow functions.
function findUser(int $id): array { if ($id <= 0) { throw new InvalidArgumentException("Bad id"); } return ["id" => $id]; } $port = $_ENV["PORT"] ?? throw new RuntimeException("PORT is not set");
Catch by type
Wrap risky calls in try and handle each failure with a matching
catch block. The first block with a compatible type wins.
Put specific types first and general types last, otherwise the general block hides the rest.
try { $user = findUser(-5); echo $user["id"]; } catch (InvalidArgumentException $e) { echo "Fix the id"; } catch (Throwable $e) { echo "Something failed"; }
finally always runs
A finally block runs whether the code succeeds, throws, or returns early.
It is the right place to close files, unlock resources, and stop timers.
Keep it small and exception free so it never masks the original error.
$lock = fopen("lock.txt", "w"); try { echo "work"; } catch (Throwable $e) { echo "failed"; } finally { fclose($lock); }
Your own exception class
Create a domain exception by extending Exception or
RuntimeException. Callers can then catch your failure without
catching every unrelated error.
Remember the split in the engine: Exception is for logic failures and
Error is for engine failures. Catch Throwable
when you must handle both branches at once.
class UserNotFound extends RuntimeException { } try { throw new UserNotFound("Ada is missing"); } catch (UserNotFound $e) { echo $e->getMessage(); }
Next: Strict types
Article author: Arthur Isaev