throw
In PHP, the "throw" keyword is used to trigger an exception. Exceptions are a way to handle errors and unexpected conditions in your code. In this article,
The PHP throw Keyword
The throw keyword stops normal execution at the point it runs and raises an exception — an object that signals something went wrong. Control immediately jumps out of the current function and up the call stack until it reaches a matching catch block. If no catch matches, PHP halts the script with a fatal error.
This page covers the syntax of throw, when to use it instead of returning an error value, how to throw built-in and custom exceptions, re-throwing and chaining, and the PHP 8 feature that lets throw be used as an expression. For the wider picture see Exceptions in PHP and the try/catch/finally flow.
Syntax
throw new Exception("Error message here");throw must be given a value that is an instance of Throwable — in practice an Exception (or one of its subclasses) or an Error. The string passed to the constructor becomes the exception message, which you read later with getMessage().
Because a thrown exception unwinds the stack, any code after throw in the same block never runs:
throw new Exception("stop here");
echo "this line is unreachable"; // never executesWhy throw instead of returning an error?
Returning a special value (like false or -1) to signal failure forces every caller to remember to check it, and the meaning of the value is easy to lose. throw makes failure impossible to ignore: the exception propagates automatically until something handles it, and it carries a message, a code, a stack trace, and the file and line where it happened.
Use throw for exceptional conditions that the current function cannot sensibly recover from — invalid arguments, a failed database connection, a missing required file — and let a caller higher up decide what to do.
A basic example
Here a divide() function throws when asked to divide by zero, and the caller catches it:
<?php
function divide(int $numerator, int $denominator): float
{
if ($denominator === 0) {
throw new InvalidArgumentException("Cannot divide by zero.");
}
return $numerator / $denominator;
}
try {
echo divide(10, 2), PHP_EOL; // 5
echo divide(10, 0), PHP_EOL; // throws before printing
} catch (InvalidArgumentException $e) {
echo "Caught: " . $e->getMessage() . PHP_EOL;
}Output:
5
Caught: Cannot divide by zero.The first call succeeds and prints 5. The second call throws, so its echo never runs and control jumps straight to the catch block.
Throwing a custom exception
Extending Exception lets you give each error type its own name, so callers can catch exactly the failures they care about and ignore the rest:
<?php
class InsufficientFundsException extends Exception {}
function withdraw(float $balance, float $amount): float
{
if ($amount > $balance) {
throw new InsufficientFundsException(
"Cannot withdraw $amount; balance is only $balance."
);
}
return $balance - $amount;
}
try {
echo withdraw(100, 250), PHP_EOL;
} catch (InsufficientFundsException $e) {
echo "Declined: " . $e->getMessage() . PHP_EOL;
}Output:
Declined: Cannot withdraw 250; balance is only 100.See Custom exception classes for more on extending Exception.
Exception message, code, and previous exception
The Exception constructor accepts three arguments — message, code, and a previous exception. The third lets you wrap a low-level error in a more meaningful one without losing the original cause (this is called exception chaining):
<?php
try {
try {
throw new RuntimeException("Disk read failed", 13);
} catch (RuntimeException $low) {
// Re-throw a higher-level exception, keeping the original as the cause.
throw new Exception("Could not load config", 0, $low);
}
} catch (Exception $e) {
echo $e->getMessage() . PHP_EOL; // Could not load config
echo "Caused by: " . $e->getPrevious()->getMessage() . PHP_EOL; // Disk read failed
echo "Original code: " . $e->getPrevious()->getCode() . PHP_EOL; // 13
}Output:
Could not load config
Caused by: Disk read failed
Original code: 13Re-throwing in a catch block
You do not have to fully handle an exception where you catch it. A catch block can do some work (log it, add context) and then throw again to let an outer handler finish the job:
<?php
function loadUser(int $id): array
{
try {
throw new RuntimeException("Database is down");
} catch (RuntimeException $e) {
error_log("loadUser($id) failed: " . $e->getMessage());
throw $e; // pass it on
}
}
try {
loadUser(7);
} catch (RuntimeException $e) {
echo "Handled at top level: " . $e->getMessage() . PHP_EOL;
}Output:
Handled at top level: Database is downthrow as an expression (PHP 8+)
Since PHP 8.0, throw is an expression, not just a statement, so you can use it in places that expect a value — like the ?: and ?? operators or an arrow function:
<?php
function getConfig(array $config, string $key): string
{
// Throw inline when the key is missing.
return $config[$key] ?? throw new InvalidArgumentException("Missing key: $key");
}
echo getConfig(['env' => 'prod'], 'env'), PHP_EOL; // prod
try {
getConfig(['env' => 'prod'], 'region');
} catch (InvalidArgumentException $e) {
echo $e->getMessage() . PHP_EOL;
}Output:
prod
Missing key: regionCommon mistakes
- Throwing without a
try/catchanywhere up the stack. An uncaught exception becomes a fatal error and stops the script. Always catch it somewhere, or register aset_exception_handler()fallback. - Throwing a string or array.
throwrequires an object implementingThrowable;throw "oops";is a syntax error. - Swallowing exceptions silently. An empty
catchblock hides bugs. At minimum log the message, or re-throw. - Using exceptions for ordinary control flow. Throwing on every expected branch (for example, "user not found" during a routine lookup) is slow and confusing — reserve it for genuinely exceptional cases.
Summary
throwraises aThrowableand immediately unwinds the stack to the nearest matchingcatch.- Prefer it over magic return values so failures cannot be silently ignored.
- Subclass
Exceptionto create named error types; pass apreviousexception to chain causes. - Catch, add context, and
throwagain to let an outer handler decide. - In PHP 8+,
throwworks as an expression inside??,?:, and arrow functions.
Continue with the try block, the catch block, and finally to see the full exception-handling cycle.