W3docs

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 executes

Why 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: 13

Re-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 down

throw 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: region

Common mistakes

  • Throwing without a try/catch anywhere up the stack. An uncaught exception becomes a fatal error and stops the script. Always catch it somewhere, or register a set_exception_handler() fallback.
  • Throwing a string or array. throw requires an object implementing Throwable; throw "oops"; is a syntax error.
  • Swallowing exceptions silently. An empty catch block 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

  • throw raises a Throwable and immediately unwinds the stack to the nearest matching catch.
  • Prefer it over magic return values so failures cannot be silently ignored.
  • Subclass Exception to create named error types; pass a previous exception to chain causes.
  • Catch, add context, and throw again to let an outer handler decide.
  • In PHP 8+, throw works as an expression inside ??, ?:, and arrow functions.

Continue with the try block, the catch block, and finally to see the full exception-handling cycle.

Practice

Practice
What does the 'throw' statement do in PHP?
What does the 'throw' statement do in PHP?
Was this page helpful?