PHP 8.0 — Throw as expression
Intermediate5 min read·php-09-009
Concept
PHP 8.0 made throw an expression — it can now be used anywhere an expression is valid: in ternary operators, arrow functions, null coalescing, and the right-hand side of &&/||. Previously, throw was a statement that could only appear on its own line.
Why this matters: It enables inline error handling without extracting helper functions or writing multi-line conditionals. Validation code becomes more compact and readable.
Common patterns:
$value ?? throw new InvalidArgumentException('Required')— throw in null coalescing: if$valueis null, throw the exception.$user ?: throw new UserNotFoundException()— throw in Elvis operator.$valid || throw new ValidationException()— throw in short-circuit||.- Arrow function:
fn($x) => $x > 0 ? $x : throw new \InvalidArgumentException('Must be positive'). matcharm:match($val) { 'ok' => 'fine', default => throw new \RuntimeException() }.
Idiomatic use: The most common practical use is the ?? throw pattern for required constructor arguments or for converting null returns from a repository into exceptions.
Code Example
php
<?php
declare(strict_types=1);
// throw in null coalescing — replace required field check
function createUser(array $data): array
{
$name = $data['name'] ?? throw new \InvalidArgumentException('name is required');
$email = $data['email'] ?? throw new \InvalidArgumentException('email is required');
return compact('name', 'email');
}
createUser(['name' => 'Alice', 'email' => 'alice@ex.com']); // ok
// createUser(['name' => 'Alice']); // throws: email is required
// throw in ternary
function getAge(array $user): int
{
return is_int($user['age'] ?? null)
? $user['age']
: throw new \InvalidArgumentException("Invalid age value");
}
// throw in arrow function
$parsePositive = fn(int $n) => $n > 0
? $n
: throw new \InvalidArgumentException("Must be positive, got $n");
echo $parsePositive(5); // 5
// $parsePositive(-1); // throws
// throw in match
function getLabel(int $code): string
{
return match($code) {
200 => 'OK',
404 => 'Not Found',
500 => 'Server Error',
default => throw new \RuntimeException("Unknown code: $code"),
};
}
// throw with || (assert-style)
function assertPositive(int $n): int
{
return ($n > 0) || throw new \RangeException("Expected positive, got $n");
// Note: this returns the result of ||: either true or throws
// For cleaner code, use: return $n > 0 ? $n : throw ...
}
// Repository pattern — throw on not found
class UserRepository
{
private array $users = [1 => ['id' => 1, 'name' => 'Alice']];
public function findOrFail(int $id): array
{
return $this->users[$id]
?? throw new \RuntimeException("User $id not found");
}
}
$repo = new UserRepository();
echo $repo->findOrFail(1)['name']; // 'Alice'
// $repo->findOrFail(999); // throws