PHP 8 didn't just arrive โ it arrived with a manifesto. Named arguments, fibers, enums, the JIT compiler, match expressions, readonly properties, union types, the nullsafe operator, and a raft of deprecations that finally cleared out two decades of cruft. If you're still writing PHP 7-style code on a PHP 8.x runtime, you're leaving significant clarity, safety, and performance on the table.
This guide is a practical tour of the features that actually matter in day-to-day work, with real-world examples drawn from production Drupal, Laravel, and API backend code.
1. Named Arguments & Fibers
Named Arguments (PHP 8.0) let you pass arguments to any function by parameter name, in any order, skipping optional parameters you don't need:
// Before: you had to remember positional order
array_slice($array, 0, null, true);
// After: intent is crystal-clear
array_slice(array: $array, offset: 0, preserve_keys: true);
This is a productivity win in heavily parameterised APIs โ particularly useful with Drupal's EntityQuery, FormState, and RenderArray patterns.
Fibers (PHP 8.1) bring cooperative concurrency to PHP without requiring ReactPHP or Amp. A Fiber is a lightweight, interruptible execution unit โ think of it as a green thread you control manually:
$fiber = new Fiber(function(): string {
$value = Fiber::suspend('first');
return 'done, received: ' . $value;
});
$first = $fiber->start(); // 'first'
$result = $fiber->resume('hello'); // 'done, received: hello'
Fibers underpin the async I/O primitives in modern PHP runtimes like Swoole and AMPHP 3, and are the foundation of non-blocking Drupal request handling in high-concurrency deployments.
2. Enums & Readonly Properties
Enums (PHP 8.1) replace the sprawling class-constant anti-pattern that every PHP codebase accumulated over years:
enum Status: string {
case Draft = 'draft';
case Published = 'published';
case Archived = 'archived';
}
// Type-safe, autocompleted, comparable
function publish(Status $status): void {
if ($status === Status::Draft) { /* ... */ }
}
Backed enums (with a string or int value) are particularly useful for mapping to database columns and Drupal field values without a translation layer.
Readonly Properties (PHP 8.1, extended in 8.2 to readonly classes) enforce immutability at the language level:
class BlogPost {
public function __construct(
public readonly int $id,
public readonly string $title,
public readonly \DateTimeImmutable $publishedAt,
) {}
}
Once set in the constructor, these properties cannot be modified. This makes value objects and DTOs trivially safe โ no need for private properties + getters.
3. The Match Expression
The match expression is switch, redesigned for the type-safe era. It uses strict comparison, returns a value, throws UnhandledMatchError on no match, and supports multiple conditions per arm:
$label = match(true) {
$score >= 90 => 'Excellent',
$score >= 75 => 'Good',
$score >= 60 => 'Pass',
default => 'Fail',
};
// Multi-condition arm
$type = match($ext) {
'jpg', 'jpeg', 'webp' => 'image',
'mp4', 'mov' => 'video',
default => 'other',
};
4. Union Types & the Nullsafe Operator
Union types let you declare that a parameter or return value can be one of several types. Combined with the nullsafe operator (?->), null-path code becomes dramatically cleaner:
// Union type: accepts int or float
function divide(int|float $a, int|float $b): int|float {
return $a / $b;
}
// Nullsafe operator chains โ no more nested null checks
$city = $order?->getUser()?->getAddress()?->getCity();
5. JIT Compiler & Performance
PHP 8.0 shipped a JIT (Just-In-Time) compiler built on top of OPcache. For most web applications the gains are modest โ 5โ15% on CPU-bound workloads โ because the bottleneck is typically I/O (database, cache, network). But for computational PHP (image processing, CSV transforms, mathematical operations) the JIT can deliver 2โ3ร speedups.
Enable it in php.ini:
opcache.enable=1
opcache.jit=tracing
opcache.jit_buffer_size=128M
In our Drupal benchmarks, enabling JIT with tracing mode reduced average page generation time by 11% on a content-heavy site with complex Views and computed fields.
6. Attributes (PHP 8.0)
Attributes replace docblock annotations with a first-class, compile-time-parseable syntax. Frameworks like Symfony 6+ and Drupal 11 use them extensively:
#[Route('/api/posts', methods: ['GET'])]
#[IsGranted('ROLE_EDITOR')]
public function listPosts(): JsonResponse { /* ... */ }
// Drupal 11 hook declaration
#[Hook('entity_presave')]
public function onEntityPresave(EntityInterface $entity): void { /* ... */ }
7. When to Upgrade
PHP 8.3 is the current stable release and the minimum for Drupal 11. PHP 7.4 reached end-of-life in November 2022 โ if you're still on it, you're running unpatched security vulnerabilities in production. Our upgrade path recommendation:
- PHP 7.4 โ 8.1 in one jump (if on Drupal 9.x โ move to 10/11 first)
- PHP 8.1 โ 8.3 is straightforward โ run
phpstanandphp-cs-fixerfirst - Drupal-specific: use
drupal-checkto flag deprecated API usage before upgrading PHP
PHP 8 is not just a version bump โ it's a language that rewards modern patterns. Enums, readonly classes, match expressions, and fibers will make your Drupal and API backends cleaner, faster, and considerably easier to maintain.