try wraps code that might throw an exception. catch handles it.
<?php
try {
$result = intdiv(10, 0);
echo "Result: $result"; // skipped
} catch (DivisionByZeroError $e) {
echo "Cannot divide by zero";
}
echo "\nThe script continues.";
Cannot divide by zero
The script continues.
When an exception is thrown inside try, PHP skips the rest of the try block and jumps to the matching catch. After the catch, the script goes on.
Several catch blocks
PHP checks the catch blocks from top to bottom and uses the first one that matches. Put the most specific exception first.
<?php
function load(string $json): array
{
return json_decode($json, true, 512, JSON_THROW_ON_ERROR);
}
try {
load("{bad json");
} catch (JsonException $e) {
echo "Invalid JSON\n";
} catch (Exception $e) {
echo "Some other exception\n";
}
Invalid JSON
One handler for several types
Use | to catch more than one class in one block.
<?php
try {
throw new InvalidArgumentException("bad value");
} catch (InvalidArgumentException | RangeException $e) {
echo "Input problem: " . $e->getMessage();
}
Input problem: bad value
catch without a variable (PHP 8.0+)
If you do not need the exception object, leave out the variable.
<?php
try {
throw new RuntimeException("x");
} catch (RuntimeException) {
echo "Something failed";
}
Something failed
Catching everything
catch (Throwable $e) catches exceptions and errors. Use it only at the edge of your program (to log and show a safe message), not deep inside code.
<?php
try {
echo strlen([]);
} catch (Throwable $e) {
echo get_class($e);
}
TypeError
Do not swallow exceptions
An empty catch hides problems.
<?php
try {
saveOrder($order);
} catch (Exception $e) {
// silence: the order is lost and nobody knows
}
Always do something: log it, tell the user, retry, or rethrow.
Rethrow with context
If you cannot handle an exception fully, wrap it in a new one and keep the original as previous.
<?php
function readConfig(string $file): array
{
try {
return json_decode(file_get_contents($file), true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
throw new RuntimeException("Config file $file is broken", 0, $e);
}
}
try {
file_put_contents("bad.json", "{oops");
readConfig("bad.json");
} catch (RuntimeException $e) {
echo $e->getMessage() . "\n";
echo get_class($e->getPrevious());
}
Config file bad.json is broken
JsonException
Where to catch
Catch an exception where you can do something useful about it. A small helper function usually should not catch it, but let it travel up to code that knows what the user should see.
Exercise: a safe division
Write safeDivide(int $a, int $b): string that returns the result as text, or "Cannot divide by zero" if the division fails. Use try and catch.
Show a possible solution
<?php
function safeDivide(int $a, int $b): string
{
try {
return (string) intdiv($a, $b);
} catch (DivisionByZeroError) {
return "Cannot divide by zero";
}
}
echo safeDivide(9, 3) . "\n";
echo safeDivide(1, 0);
3
Cannot divide by zero