Tutorial

PHP 8.4 New Features: Property Hooks, HTML5 Parser, and Performance

May 06, 2026

Back to Blog

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

// PHP 8.3 and earlier - verbose boilerplate
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

// PHP 8.4 - clean, expressive 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)
Key benefits of property hooks: Less boilerplate code, validation logic lives next to the property it validates, virtual/computed properties without explicit getter methods, and the ability to use shorthand arrow syntax for simple transformations. Property hooks work with promoted constructor parameters too.

Property Hooks in Constructor Promotion

One of the most powerful combinations is using property hooks with constructor parameter promotion:

class Product {
  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)

class BankAccount {
  private float $balance;

  public function getBalance(): float {
    return $this->balance;
  }
}
// Need a getter method

After (PHP 8.4)

class BankAccount {
  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.

// Old way (PHP 8.3) - HTML5 warnings everywhere
$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');
CSS selector support: The new DOM API includes 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:

FunctionPurposeReturns
array_find()Find first element matching a callbackThe matching value (or null)
array_find_key()Find key of first matching elementThe matching key (or null)
array_any()Check if any element matchesbool
array_all()Check if all elements matchbool
$users = [
  ['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:

// New mb_ functions in PHP 8.4
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:

// Before PHP 8.4
$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:

Key deprecations to watch for:
  • implode() with reversed arguments (array first, separator second) now triggers a deprecation notice
  • Passing null to non-nullable internal function parameters continues to generate deprecation notices (started in 8.1)
  • The MYSQLI_SET_CHARSET_DIR constant is deprecated
  • Using _ as a class name is deprecated (reserved for future use)
  • The session.sid_length and session.sid_bits_per_character ini 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.

5-8%
Faster Than PHP 8.3 (benchmarks)
35%
Faster Than PHP 7.4 (real apps)

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 VersionRequests/secAvg Response TimeMemory Peak
PHP 7.4128 req/s78ms42MB
PHP 8.0162 req/s62ms38MB
PHP 8.1171 req/s58ms36MB
PHP 8.2178 req/s56ms35MB
PHP 8.3185 req/s54ms34MB
PHP 8.4196 req/s51ms33MB

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:

1
Check your framework compatibility. Laravel 11+, Symfony 7+, WordPress 6.4+, and Drupal 10.2+ all support PHP 8.4. Check your specific version requirements.
2
Run your test suite on PHP 8.4. Install PHP 8.4 alongside your current version and run your tests. Most issues will surface as deprecation notices, not errors.
3
Update Composer dependencies. Run 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.
4
Address deprecation notices. Use error_reporting(E_ALL) in development to catch all deprecation notices. Fix them now to avoid issues when PHP 9.0 removes these features.
5
Adopt new features gradually. Start using property hooks, asymmetric visibility, and the new array functions in new code. Refactor existing code when you touch it.
Extension compatibility: Before upgrading, verify that all PHP extensions your application uses have PHP 8.4 compatible versions. Common extensions like curl, mbstring, gd, and intl are supported from day one, but niche extensions may take longer to update.

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.

$reflector = new ReflectionClass(HeavyService::class);

// 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::PositiveInfinity); // 3
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.

Panelica PHP management features:
  • 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.

Share:
See the Demo