PHP 8.4: The Most Developer-Friendly Release Yet
PHP 8.4, released in November 2024, continues PHP's remarkable renaissance. After PHP 8.0 brought us JIT compilation and named arguments, 8.1 introduced enums and fibers, 8.2 added readonly classes, and 8.3 delivered typed class constants, PHP 8.4 focuses on making everyday code cleaner and more expressive. The headline features are property hooks (inspired by Kotlin and C#), asymmetric visibility, and a brand-new HTML5 parser that finally brings PHP's DOM handling into the modern era.
Whether you're running WordPress, Laravel, Symfony, or a custom application, PHP 8.4 delivers meaningful improvements in code quality, performance, and developer experience. Let's explore every major feature with practical examples.
Property Hooks: The End of Boilerplate Getters and Setters
Property hooks are arguably the most significant language feature added to PHP since enums. They allow you to define get and set behavior directly on class properties, eliminating the need for explicit getter/setter methods and the boilerplate that comes with them.
Before PHP 8.4: The Old Way
class User {
private string $firstName;
private string $lastName;
public function getFirstName(): string {
return $this->firstName;
}
public function setFirstName(string $value): void {
if (strlen($value) === 0) {
throw new ValueError('Name cannot be empty');
}
$this->firstName = ucfirst(trim($value));
}
public function getFullName(): string {
return "{$this->firstName} {$this->lastName}";
}
}
After PHP 8.4: Property Hooks
class User {
public string $firstName {
set(string $value) {
if (strlen($value) === 0) {
throw new ValueError('Name cannot be empty');
}
$this->firstName = ucfirst(trim($value));
}
}
public string $lastName {
set(string $value) => $this->lastName = ucfirst(trim($value));
}
public string $fullName {
get => "{$this->firstName} {$this->lastName}";
}
}
$user = new User();
$user->firstName = 'john';
echo $user->firstName; // "John" (auto-capitalized)
echo $user->fullName; // "John Doe" (virtual property)
Property Hooks in Constructor Promotion
One of the most powerful combinations is using property hooks with constructor parameter promotion:
public function __construct(
public string $name,
private float $price {
set(float $value) {
if ($value < 0) throw new ValueError('Price cannot be negative');
$this->price = round($value, 2);
}
},
) {}
public string $formattedPrice {
get => '$' . number_format($this->price, 2);
}
}
Asymmetric Visibility: Read Public, Write Private
PHP 8.4 introduces asymmetric visibility, allowing you to set different access levels for reading and writing a property. The most common use case is properties that are publicly readable but can only be modified from within the class.
Before (PHP 8.3)
private float $balance;
public function getBalance(): float {
return $this->balance;
}
}
// Need a getter method
After (PHP 8.4)
public private(set) float $balance;
// No getter needed!
}
echo $account->balance; // OK
$account->balance = 100; // Error!
The syntax is intuitive: public private(set) means "public for reading, private for writing." You can also use public protected(set) for properties that child classes can modify but external code cannot.
The New HTML5 DOM Parser
PHP's old DOMDocument class used the libxml2 HTML parser, which only understands HTML 4.01. This meant that modern HTML5 elements like <main>, <section>, <nav>, and <template> would trigger warnings or be parsed incorrectly. PHP 8.4 introduces \Dom\HTMLDocument with a proper HTML5 parser.
$dom = new DOMDocument();
@$dom->loadHTML($html); // @ to suppress warnings
// New way (PHP 8.4) - proper HTML5 support
$dom = \Dom\HTMLDocument::createFromString($html);
$dom = \Dom\HTMLDocument::createFromFile('page.html');
$dom = \Dom\HTMLDocument::createEmpty();
// CSS selector support!
$elements = $dom->querySelectorAll('div.card > h2');
$nav = $dom->querySelector('nav.main-menu');
querySelector() and querySelectorAll(), matching the browser JavaScript API. No more complex XPath expressions for simple element selection. This alone makes HTML parsing in PHP dramatically more intuitive.
New Array Functions
PHP 8.4 adds four new array functions that reduce the need for verbose array_filter and foreach patterns:
| Function | Purpose | Returns |
|---|---|---|
array_find() | Find first element matching a callback | The matching value (or null) |
array_find_key() | Find key of first matching element | The matching key (or null) |
array_any() | Check if any element matches | bool |
array_all() | Check if all elements match | bool |
['name' => 'Alice', 'role' => 'admin'],
['name' => 'Bob', 'role' => 'user'],
['name' => 'Charlie', 'role' => 'moderator'],
];
// Find first admin
$admin = array_find($users, fn($u) => $u['role'] === 'admin');
// ['name' => 'Alice', 'role' => 'admin']
// Check if any user is an admin
$hasAdmin = array_any($users, fn($u) => $u['role'] === 'admin');
// true
// Check if all users are verified
$allAdmins = array_all($users, fn($u) => $u['role'] === 'admin');
// false
// Before PHP 8.4, you needed:
$admin = current(array_filter($users, fn($u) => $u['role'] === 'admin')) ?: null;
// Much less readable!
New Multibyte String Functions
PHP 8.4 adds several new mb_ functions that bring multibyte string handling closer to parity with single-byte functions:
mb_trim(' Hello World '); // "Hello World"
mb_ltrim(' Hello'); // "Hello"
mb_rtrim('Hello '); // "Hello"
mb_ucfirst('hello world'); // "Hello world"
mb_lcfirst('Hello World'); // "hello World"
// These properly handle Unicode characters like
// German umlauts, Chinese characters, emoji, etc.
mb_ucfirst('ubermensch'); // Works correctly with Unicode
Method Chaining Without Temporary Variables
PHP 8.4 allows calling methods directly on new expressions without wrapping them in parentheses:
$result = (new DateTime())->format('Y-m-d');
$length = (new ReflectionClass(Foo::class))->getMethods();
// PHP 8.4 - no parentheses needed
$result = new DateTime()->format('Y-m-d');
$methods = new ReflectionClass(Foo::class)->getMethods();
Deprecated Features in PHP 8.4
Every PHP release deprecates features that will be removed in future versions. Here's what's on the chopping block in 8.4:
implode()with reversed arguments (array first, separator second) now triggers a deprecation notice- Passing
nullto non-nullable internal function parameters continues to generate deprecation notices (started in 8.1) - The
MYSQLI_SET_CHARSET_DIRconstant is deprecated - Using
_as a class name is deprecated (reserved for future use) - The
session.sid_lengthandsession.sid_bits_per_characterini settings are deprecated
Performance Improvements
PHP 8.4 continues the performance trajectory that has made PHP one of the fastest interpreted languages. While the improvements are more incremental compared to the massive JIT gains in 8.0, they add up in real-world applications.
The performance gains come from several internal optimizations:
- Improved JIT compiler with better optimization passes and reduced overhead
- Optimized property access patterns, especially beneficial for frameworks
- Reduced memory consumption for class instances through internal layout improvements
- Faster array operations, particularly for the new array_find/any/all functions which are implemented in C rather than userland PHP
- DOM parser performance improvements for HTML processing workloads
Real-World WordPress Benchmark
| PHP Version | Requests/sec | Avg Response Time | Memory Peak |
|---|---|---|---|
| PHP 7.4 | 128 req/s | 78ms | 42MB |
| PHP 8.0 | 162 req/s | 62ms | 38MB |
| PHP 8.1 | 171 req/s | 58ms | 36MB |
| PHP 8.2 | 178 req/s | 56ms | 35MB |
| PHP 8.3 | 185 req/s | 54ms | 34MB |
| PHP 8.4 | 196 req/s | 51ms | 33MB |
Migration Guide: From PHP 8.3 to 8.4
Upgrading from PHP 8.3 to 8.4 is relatively smooth. Most applications will work without modification. Here's a step-by-step approach:
composer update to get the latest versions of your dependencies that support PHP 8.4. Check composer.json for any PHP version constraints that need updating.error_reporting(E_ALL) in development to catch all deprecation notices. Fix them now to avoid issues when PHP 9.0 removes these features.More PHP 8.4 Features Worth Knowing
Lazy Objects (RFC Accepted)
PHP 8.4 introduces lazy object initialization through the Reflection API. A lazy object is created as a lightweight proxy that only initializes its full state when first accessed. This is particularly useful for dependency injection containers and ORM frameworks.
// Create a lazy proxy - HeavyService constructor NOT called yet
$service = $reflector->newLazyGhost(function (HeavyService $s) {
$s->__construct(/* expensive dependencies */);
});
// Constructor called NOW, on first property access
$result = $service->process();
New Rounding Modes for round()
The round() function now supports four additional rounding modes via the RoundingMode enum:
round(2.5, 0, RoundingMode::NegativeInfinity); // 2
round(2.5, 0, RoundingMode::TowardsZero); // 2
round(2.5, 0, RoundingMode::AwayFromZero); // 3
PHP 8.4 on Panelica
Panelica supports PHP versions 8.1 through 8.4 with per-user, per-version PHP-FPM pools. This means you can run PHP 8.4 for your latest Laravel project while keeping PHP 8.1 for a legacy WordPress site, all on the same server without any conflicts.
- Switch PHP versions per domain with a single click from the panel
- Individual php.ini settings per user and per PHP version
- OPcache management with per-pool configuration
- PHP extension management: enable/disable extensions per version
- Per-user PHP-FPM pools with isolated resource limits via Cgroups v2
- Side-by-side version support: run PHP 8.1, 8.2, 8.3, and 8.4 simultaneously
Upgrading a domain from PHP 8.3 to 8.4 on Panelica takes seconds: go to the domain settings, select PHP 8.4 from the version dropdown, and save. Panelica creates a new PHP-FPM pool for the updated version while keeping the previous configuration available for instant rollback if needed.
Conclusion
PHP 8.4 is a polished, developer-focused release that makes everyday PHP code cleaner and more expressive. Property hooks eliminate getter/setter boilerplate, asymmetric visibility reduces the need for manual encapsulation patterns, the HTML5 parser brings DOM handling into the modern era, and the new array functions make collection operations more readable.
The performance improvements, while incremental, continue PHP's remarkable performance trajectory. A modern PHP 8.4 application runs roughly 50% faster than the same code on PHP 7.4, using less memory. If you're still on PHP 7.x or early 8.x versions, upgrading to 8.4 is one of the easiest performance wins you can get.
Start testing your applications on PHP 8.4 today. The migration is smooth, the new features are genuinely useful, and the performance is the best PHP has ever offered.