PHP 8 New Features Cheat Sheet
Covers PHP 8.0-8.4 additions: named arguments, enums, readonly properties, match expressions, attributes, fibers, and typed class constants.
Named Arguments & `match`
Named args (8.0) improve call-site readability; `match` (8.0) is a strict, expression-based switch.
function createUser(string $name, string $role = 'user', bool $active = true) {}createUser(name: 'Ada', role: 'admin'); // skip positional order, skip $active$status = 200;$message = match (true) { $status >= 200 && $status < 300 => 'Success', $status >= 400 && $status < 500 => 'Client Error', $status >= 500 => 'Server Error', default => 'Unknown',};// match uses strict (===) comparison and has no fallthrough
Enums & Readonly Properties
Backed enums (8.1) and readonly properties (8.1) for immutable, type-safe value objects.
enum Status: string{ case Draft = 'draft'; case Published = 'published'; case Archived = 'archived'; public function label(): string { return match ($this) { self::Draft => 'Draft', self::Published => 'Published', self::Archived => 'Archived', }; }}class Point{ public function __construct( public readonly float $x, public readonly float $y, ) {}}$p = new Point(1.0, 2.0);// $p->x = 5.0; // Error: Cannot modify readonly property Point::$x
Attributes & Nullsafe Operator
Attributes (8.0) replace docblock annotations; `?->` (8.0) short-circuits on null.
#[Attribute]class Route{ public function __construct(public string $path, public string $method = 'GET') {}}class UserController{ #[Route('/users/{id}', method: 'GET')] public function show(int $id) {}}// Nullsafe chaining — returns null instead of throwing if any link is null$city = $user?->getAddress()?->getCity();// Constructor property promotion (8.0)class Money{ public function __construct( private int $amount, private string $currency = 'USD', ) {}}
PHP 8.2-8.4 Additions
Readonly classes, typed class constants, and the new array_find family.
// 8.2: readonly classes — every property is readonly automaticallyreadonly class Coordinates{ public function __construct( public float $lat, public float $lng, ) {}}// 8.3: typed class constantsclass Config{ public const string VERSION = '2.4.0';}// 8.4: new array functions$users = [['name' => 'Ada', 'age' => 30], ['name' => 'Grace', 'age' => 25]];$found = array_find($users, fn($u) => $u['age'] < 28);// property hooks (8.4) — computed getters/setters without boilerplateclass Temperature{ public float $celsius = 0; public float $fahrenheit { get => $this->celsius * 9 / 5 + 32; set => $this->celsius = ($value - 32) * 5 / 9; }}
Feature-to-Version Map
Quick lookup for which release introduced what.
- 8.0- named args, match, nullsafe ?->, attributes, union types, constructor promotion
- 8.1- enums, readonly properties, fibers, never return type, first-class callable syntax
- 8.2- readonly classes, disjunctive normal form (DNF) types, standalone null/false types
- 8.3- typed class constants, #[Override] attribute, json_validate()
- 8.4- property hooks, asymmetric visibility, array_find/array_any/array_all
- Deprecated in 8.x- dynamic properties (8.2), implicit nullable types warning tightened
Fibers (8.1) — Cooperative Coroutines
Fiber gives PHP pausable/resumable execution contexts, the low-level primitive async frameworks build on.
$fiber = new Fiber(function (): void { $value = Fiber::suspend('fiber suspended'); echo "Resumed with: $value\n";});$result = $fiber->start();echo $result . "\n"; // "fiber suspended"$fiber->resume('resumed value');// prints: Resumed with: resumed value// Fibers are cooperative, not preemptive — you must explicitly suspend/resume.// Libraries like Amp and ReactPHP v3 use them to implement async/await-style APIs// without callback hell, while staying single-threaded.
First-Class Callable Syntax (8.1)
`func(...)` converts any function, method, or static method reference into a proper Closure — no strings, no arrays.
class Calculator{ public function add(int $a, int $b): int { return $a + $b; } public static function multiply(int $a, int $b): int { return $a * $b; }}$calc = new Calculator();$addFn = $calc->add(...); // bound instance method as Closure$mulFn = Calculator::multiply(...);echo $addFn(2, 3); // 5echo $mulFn(2, 3); // 6$strlenFn = strlen(...); // works for built-in functions tooprint_r(array_map(strtoupper(...), ['a', 'b']));
Enums Implementing Interfaces
Backed and pure enums can implement interfaces and declare their own constants, just like classes.
interface HasColor{ public function color(): string;}enum Suit: string implements HasColor{ case Hearts = 'H'; case Spades = 'S'; const Wild = self::Spades; // enums can declare their own constants public function color(): string { return match ($this) { self::Hearts => 'red', self::Spades => 'black', }; }}function describe(HasColor $c): string{ return $c->color();}describe(Suit::Hearts); // enums satisfy interface type hints like ordinary classes
Asymmetric Visibility (8.4)
Declare a property publicly readable but only privately writable, eliminating boilerplate getter/setter pairs.
class Order{ public private(set) string $status = 'pending'; public function ship(): void { $this->status = 'shipped'; // allowed: write happens inside the declaring class }}$o = new Order();echo $o->status; // OK — public read// $o->status = 'cancelled'; // Fatal error: Cannot modify private(set) property Order::$status from global scope
Lesser-Known PHP 8.x APIs
Smaller additions that matter once you're past the headline features.
- WeakMap- maps objects to values without preventing garbage collection of the key objects; ideal for per-object metadata caches
- Stringable- implicit interface auto-added to any class defining __toString(), usable directly in type hints
- #[SensitiveParameter]- marks an argument (e.g. a password) so its value is redacted from stack traces and error logs
- Random\Engine / Randomizer- object-oriented, independently seedable random number generators (8.2), replacing global mt_rand() state
- DNF types- disjunctive normal form types like (Countable&Traversable)|null combine unions and intersections (8.2)
- never return type- declares a function never returns normally (always throws or exits), aiding static analysis
- static return type- lets a method's return type follow late static binding when overridden in a subclass
- #[AllowDynamicProperties]- opts a class back into dynamic properties after they were deprecated by default in 8.2
Use `#[\Override]` (8.3) on methods that override a parent method — it's a zero-cost compile-time check that catches typos and broken overrides when a parent class signature changes.