Proper exception handling prevents silent failures and makes debugging much easier.
try {
$result = riskyOperation();
} catch (InvalidArgumentException $e) {
// handle specific exception
echo "Invalid input: " . $e->getMessage();
} catch (RuntimeException $e) {
// handle broader category
logger()->error($e->getMessage());
} finally {
// always runs, even if an exception was thrown
closeConnection();
}
class PaymentFailedException extends RuntimeException
{
public function __construct(
string $message,
private readonly string $transactionId,
int $code = 0,
?\Throwable $previous = null
) {
parent::__construct($message, $code, $previous);
}
public function getTransactionId(): string
{
return $this->transactionId;
}
}
// Throw it
throw new PaymentFailedException(
message: 'Card declined',
transactionId: 'txn_abc123',
code: 402
);
set_exception_handler(function (\Throwable $e) {
error_log($e->getMessage() . " in " . $e->getFile() . ":" . $e->getLine());
http_response_code(500);
echo json_encode(['error' => 'An unexpected error occurred.']);
exit(1);
});
All Comments