Both Error and Exception implement Throwable, so either can travel through PHP’s throw/catch mechanism. Catch expected application failures by their specific exception type. Catch Throwable mainly at a top-level boundary that must log and convert any uncaught failure into a safe response.
Last updated: October 27, 2026.
<?php
function runTask(string $mode): void
{
if ($mode === 'invalid-data') {
throw new InvalidArgumentException('Unsupported task input.');
}
if ($mode === 'programming-error') {
strlen([]); // TypeError, which extends Error.
}
}
try {
runTask($_GET['mode'] ?? 'invalid-data');
} catch (InvalidArgumentException $error) {
http_response_code(400); // Expected, specific failure.
} catch (Throwable $error) {
error_log($error->__toString());
http_response_code(500); // Unexpected boundary failure.
}The first catch handles a known input problem. The final catch prevents implementation details from reaching the browser while preserving the complete unexpected failure in the server log.
Use the hierarchy to express intent
The PHP error-handling reference separates throwable failures into the Error hierarchy for programming errors and the Exception hierarchy for recoverable failures. Examples of Error subclasses include TypeError, ValueError, and ParseError. Application code normally throws an Exception subclass for a condition callers may reasonably handle.
The Throwable reference defines the common interface. User-defined throwable classes extend Exception; they cannot implement Throwable directly. Create focused classes when callers need different responses for validation, authorization, missing data, or unavailable services.
Catch narrowly inside and broadly at the boundary
Inside business logic, catch only failures the function can resolve, translate, or enrich. A broad catch (Throwable) can conceal a programming defect and let execution continue with invalid state. If the code cannot recover, allow the failure to move upward.
At an HTTP front controller, queue worker, scheduled command, or similar outer boundary, a final Throwable handler is useful for logging, cleanup, and a generic failure response. Do not show stack traces or exception messages to visitors. Continue with safe finally cleanup, handling PHP ValueError, and debugging PHP with Xdebug.