Error Handling

Course 2 · Ch 3
Error Handling: Exceptions, try/catch/finally, Custom Exceptions
Handling things going wrong predictably, instead of letting a script crash or silently produce wrong results

Every chapter so far has assumed inputs are valid and operations succeed. Real code constantly deals with things that can fail — a file that doesn't exist, a division by zero, invalid data passed to a function. PHP's exception system gives a structured way to detect these failures and decide what to do about them, rather than letting the script crash outright or silently continue with bad data.

Throwing an Exception

<?php function divide(float $a, float $b): float { if ($b === 0.0) { throw new Exception("Cannot divide by zero"); } return $a / $b; } echo divide(10, 0); // uncaught — fatal error, script stops here ?>

throw new Exception("message") signals that something has gone wrong, immediately halting normal execution at that point. An uncaught exception — one that isn't handled anywhere — stops the entire script with a fatal error, similar to a crash.

Catching an Exception — try/catch

<?php try { echo divide(10, 0); } catch (Exception $e) { echo "Something went wrong: " . $e->getMessage(); } echo "Script keeps running after this point."; // this line DOES still run ?>

Code that might throw an exception goes inside a try block. If an exception is thrown anywhere inside it, execution immediately jumps to the matching catch block instead of crashing — $e->getMessage() retrieves the message that was passed to throw new Exception(...). Critically, the script continues running normally after the try/catch finishes.

try { ... } throws catch (Exception $e) finally { ... } Script continues
try → (if it throws) catch → finally always runs either way → script continues normally

finally — Always Runs, Exception or Not

<?php try { echo divide(10, 0); } catch (Exception $e) { echo "Caught: " . $e->getMessage() . "<br>"; } finally { echo "Cleanup runs no matter what.<br>"; // runs whether or not an exception was thrown/caught } ?>

finally runs whether the try succeeded, failed and was caught, or even if an exception inside catch itself wasn't fully handled — genuinely useful for cleanup work that absolutely must happen either way, such as closing a file or a database connection.

Custom Exceptions — More Specific Than the Built-In Exception

<?php class InsufficientFundsException extends Exception {} class BankAccount { private float $balance = 0; public function withdraw(float $amount) { if ($amount > $this->balance) { throw new InsufficientFundsException("Cannot withdraw £$amount, balance is only £{$this->balance}"); } $this->balance -= $amount; } } $account = new BankAccount(); try { $account->withdraw(50); } catch (InsufficientFundsException $e) { echo "Withdrawal failed: " . $e->getMessage(); } ?>

Custom exceptions (extending the built-in Exception class — Chapter 2's inheritance, applied here) give catch blocks the ability to react differently depending on exactly what kind of problem occurred, rather than every failure being a generic, indistinguishable "Exception."

Catching Multiple, Different Exception Types

<?php try { $account->withdraw(50); } catch (InsufficientFundsException $e) { echo "Not enough money: " . $e->getMessage(); } catch (Exception $e) { echo "Some other problem: " . $e->getMessage(); // catches anything else } ?>
Order matters — PHP checks catch blocks top to bottom, using the first one that matches
Since InsufficientFundsException IS an Exception (it extends it), placing the generic catch (Exception $e) block first would catch everything — including InsufficientFundsException — before the more specific block ever gets a chance to run. Always list the most specific exception types first, generic ones last.

PHP's Built-In Exception Hierarchy (a Glimpse)

Throwable (the root interface) └─ Exception — the general-purpose base class, extend this for custom exceptions ├─ InvalidArgumentException ├─ RuntimeException └─ (your own custom exceptions go here too) └─ Error — internal PHP engine errors (TypeError, DivisionByZeroError) — catchable, but generally indicates a programming bug rather than an expected failure

PHP actually distinguishes Exception (expected, recoverable problems you anticipate and throw deliberately) from Error (engine-level problems, like calling a method that doesn't exist) — both are catchable, but this course focuses on Exception as the type to throw deliberately in your own code.

Coding Challenges

Challenge 1

Write a function squareRoot($n) that throws an Exception if $n is negative (square roots of negative numbers aren't real numbers), otherwise returns sqrt($n). Call it inside a try/catch with both a valid and an invalid value, echoing either the result or the caught error message.

📄 View solution
Challenge 2

Create a custom exception InvalidAgeException extending Exception. Write a function setAge($age) that throws it if age is below 0 or above 130, otherwise echoes "Age set to $age." Test it with a try/catch/finally, where the finally block always echoes "Validation attempt complete."

📄 View solution
Challenge 3

Create two custom exceptions, FileNotFoundException and PermissionDeniedException, both extending Exception. Write a function openFile($filename, $hasPermission) that throws the first if $filename is an empty string, the second if $hasPermission is false, otherwise echoes "File opened successfully." Use a try block with TWO separate catch blocks (correctly ordered) to handle each case distinctly, with a generic Exception catch as a final fallback.

📄 View solution

Chapter 3 Quick Reference

  • throw new Exception("message") — signals a problem, halts normal execution at that point
  • try { } catch (Exception $e) { } — catches a thrown exception, script continues afterward
  • $e->getMessage() — retrieves the message passed when the exception was thrown
  • finally { } — always runs, exception or not; for cleanup code
  • Custom exceptions — extend Exception to create specific, distinguishable error types
  • Multiple catch blocks — list most specific exception types first, generic Exception last
  • Exception vs Error — Exception for expected/anticipated problems you throw deliberately; Error for engine-level bugs
  • Next chapter: working with databases — PDO, prepared statements, basic CRUD