catch
As a PHP developer, you may have used the "try...catch" statement to handle errors or exceptions in your code. The "catch" keyword is a key component of the
The PHP catch Keyword
When code inside a try block runs into an exception — an object that signals something went wrong — execution stops and PHP looks for a matching catch block to handle it. The catch keyword names the type of exception it can handle and binds the thrown object to a variable so you can inspect it. Without a catch, an uncaught exception becomes a fatal error and halts the script.
This page explains the catch syntax, how PHP picks which block runs, how to read details off the caught exception, and the common patterns (multiple catches, union types, re-throwing) you will use in real code.
Syntax
A catch block always follows a try block. It declares an exception type and a variable that receives the thrown object:
<?php
try {
// Code that may throw an exception
} catch (Exception $e) {
// Runs only if a matching exception is thrown above
echo $e->getMessage();
}PHP matches a catch block when the thrown object is an instance of the declared type. Because every built-in exception extends the base Exception class (and both extend the Throwable interface), catch (Exception $e) catches most exceptions. Catching Throwable additionally captures Error objects such as TypeError and DivisionByZeroError.
You can pair catch with a finally block to run cleanup code whether or not an exception occurred.
A working example
The function below throws when asked to divide by zero. The catch block intercepts that exception and reports it instead of letting the script crash:
<?php
function divide($numerator, $denominator)
{
if ($denominator == 0) {
throw new InvalidArgumentException("Division by zero.");
}
return $numerator / $denominator;
}
try {
echo divide(10, 0);
} catch (InvalidArgumentException $e) {
echo "Error: " . $e->getMessage();
}
// Output: Error: Division by zero.Notice the script keeps running after the catch — control resumes on the line following the try/catch structure rather than aborting.
Reading details from the caught exception
The variable in a catch clause ($e above) is the exception object itself. It exposes methods that describe what happened:
<?php
try {
throw new RuntimeException("Disk is full", 28);
} catch (RuntimeException $e) {
echo $e->getMessage(); // Disk is full
echo "\n";
echo $e->getCode(); // 28
echo "\n";
echo $e->getLine(); // 4 (line where it was thrown)
}| Method | Returns |
|---|---|
getMessage() | The human-readable error message |
getCode() | The integer error code passed to the constructor |
getFile() | The file in which the exception was created |
getLine() | The line number where it was thrown |
getTrace() | The stack trace as an array |
getPrevious() | The previous exception (for chained exceptions) |
Catching multiple exception types
When a try block can fail in different ways, list several catch blocks. PHP tries them top to bottom and runs the first one that matches, so order the more specific types before the general ones:
<?php
try {
// Code that may throw different exceptions
throw new InvalidArgumentException("bad input");
} catch (InvalidArgumentException $e) {
echo "Invalid argument: " . $e->getMessage();
} catch (RuntimeException $e) {
echo "Runtime problem: " . $e->getMessage();
} catch (Exception $e) {
echo "Something else: " . $e->getMessage();
}
// Output: Invalid argument: bad inputIf catch (Exception $e) came first it would swallow everything, and the more specific blocks below it would never run.
Union catch (PHP 7.1+)
When two different exception types need identical handling, combine them with a pipe | instead of duplicating the block:
<?php
try {
throw new RuntimeException("connection reset");
} catch (InvalidArgumentException | RuntimeException $e) {
echo "Handled: " . $e->getMessage();
}
// Output: Handled: connection resetNon-capturing catch (PHP 8.0+)
If you do not need the exception object, you can omit the variable entirely:
<?php
try {
throw new Exception("ignored details");
} catch (Exception) {
echo "An error occurred, retrying...";
}
// Output: An error occurred, retrying...Re-throwing and exception chaining
Sometimes a catch block should log the problem and then pass it on — or wrap a low-level exception in a more meaningful one. Pass the original as the third constructor argument to preserve the chain:
<?php
try {
try {
throw new RuntimeException("low-level failure");
} catch (RuntimeException $e) {
// Wrap and re-throw with context preserved
throw new Exception("High-level operation failed", 0, $e);
}
} catch (Exception $e) {
echo $e->getMessage(); // High-level operation failed
echo "\n";
echo $e->getPrevious()->getMessage(); // low-level failure
}Best practices
- Catch the narrowest type you can handle. A blanket
catch (Throwable $e)can hide bugs by swallowing programming errors you meant to fix. - Order specific before general. Specific subclasses must precede their parent types.
- Don't leave a
catchempty. Silently discarding an exception makes failures invisible; at minimum log it. - Throw, don't return error flags. Combine
catchwiththrowso callers can't accidentally ignore failures. - Use
finallyfor cleanup (closing files, releasing locks) that must run on both the success and failure paths.
Related topics
- PHP
try— the block thatcatchguards - PHP
throw— raising an exception - PHP
finally— guaranteed cleanup code - PHP
exception— the exception object and its methods