- PHP
- Updates
- Backend
PHP 8 Features: What's New from 8.0 to 8.5
The headline features of every PHP 8 release from 8.0 to 8.5, with runnable examples you can test across versions in the browser.
PHP 8 turned PHP into a strongly typed, expressive modern language. 8.0 introduced union types, named arguments, match and a JIT compiler, and each yearly release since has added headline features, from enums (8.1) and readonly classes (8.2) to property hooks (8.4) and the pipe operator (8.5). This guide covers the most important features release by release, with runnable examples.
Key takeaways
- PHP 8.0: union types, named arguments, constructor property promotion,
matchand JIT. - PHP 8.1: enums, readonly properties and first-class callable syntax.
- PHP 8.2 and 8.3: readonly classes and DNF types, then typed class constants and
json_validate(). - PHP 8.4 and 8.5: property hooks and asymmetric visibility, then the pipe operator,
clonewith property changes and a built-in URI extension. - You can run every example in the WebFiddle PHP sandbox and switch between PHP 8.0 and 8.5 to see which version introduced a feature.
Each section links to that release's official announcement on php.net, and every feature named here comes from those pages.
PHP 8.0
The PHP 8.0 release announcement lists named arguments, attributes, constructor property promotion, union types, the match expression, the nullsafe operator and JIT compilation among its headline features.
Union types and match
Union types let a parameter, property or return type accept more than one type without relying on PHPDoc comments. match is an expression that returns a value and, unlike switch, uses strict comparison (===):
<?php
function describe(int|float $n): string {
return match (true) {
$n < 0 => 'negative',
$n === 0, $n === 0.0 => 'zero',
default => 'positive',
};
}
echo describe(-5), ' ', describe(0), ' ', describe(3.2), PHP_EOL;
// negative zero positive
If no arm matches and there is no default, match throws an UnhandledMatchError instead of silently doing nothing.
Named arguments and constructor property promotion
Named arguments let you pass values by parameter name, so you can skip optional parameters. Here is setcookie() before and after:
<?php
// Before: pass placeholders just to reach $secure and $httponly
setcookie('name', 'value', 0, '', '', true, true);
// PHP 8: say only what you mean
setcookie(
name: 'name',
value: 'value',
secure: true,
httponly: true,
);
Constructor property promotion declares and assigns properties directly in the constructor signature:
<?php
class Point {
public function __construct(
public float $x = 0.0,
public float $y = 0.0,
) {}
}
$p = new Point(y: 2.5);
echo $p->x, ', ', $p->y, PHP_EOL; // 0, 2.5
PHP 8.0 also added a JIT compiler, which compiles hot code to machine code at runtime. It mainly helps CPU-intensive code, and typical web requests that spend most of their time waiting on databases and I/O see less benefit.
PHP 8.1
The PHP 8.1 release announcement highlights enumerations, readonly properties, first-class callable syntax, pure intersection types, the never return type and fibers.
Enums and readonly properties
<?php
enum Status: string {
case Active = 'active';
case Archived = 'archived';
public function label(): string {
return ucfirst($this->value);
}
}
final class Money {
public function __construct(public readonly int $amount) {}
}
echo Status::from('archived')->label(), PHP_EOL; // Archived
$price = new Money(100);
try {
$price->amount = 5;
} catch (Error $e) {
echo $e->getMessage(), PHP_EOL; // Cannot modify readonly property Money::$amount
}
First-class callable syntax creates a closure from any function with strlen(...).
PHP 8.2
The PHP 8.2 release announcement highlights readonly classes, disjunctive normal form (DNF) types, null, false and true as stand-alone types, the new Random extension, constants in traits, and the deprecation of dynamic properties.
Readonly classes
Marking a class readonly makes every property in it readonly:
<?php
readonly class BlogData {
public function __construct(
public string $title,
) {}
}
$post = new BlogData('Hello');
try {
$post->title = 'Changed';
} catch (Error $e) {
echo $e->getMessage(), PHP_EOL; // Cannot modify readonly property BlogData::$title
}
DNF types combine union and intersection types, as in (Countable&Traversable)|null. Creating a property that was never declared (a dynamic property) now triggers a deprecation notice.
PHP 8.3
The PHP 8.3 release announcement highlights typed class constants, dynamic class constant fetch, the #[\Override] attribute, deep-cloning of readonly properties and the new json_validate() function.
Typed class constants and json_validate()
<?php
class Config {
const string VERSION = '8.3';
}
echo Config::VERSION, PHP_EOL; // 8.3
var_dump(json_validate('{"a": 1}')); // bool(true)
var_dump(json_validate('{a: 1}')); // bool(false)
json_validate() checks whether a string is valid JSON without building the decoded array or object. #[\Override] makes PHP report an error if the method it marks doesn't actually override a parent method.
PHP 8.4
The PHP 8.4 release announcement highlights property hooks, asymmetric visibility, the #[\Deprecated] attribute, new DOM features with HTML5 support, an object API for BCMath and new array_*() functions.
Property hooks and asymmetric visibility
Property hooks attach get and set logic to a property. Asymmetric visibility lets anyone read a property while only the class can write to it:
<?php
class Country {
public string $code {
set (string $value) {
$this->code = strtoupper($value);
}
}
public function __construct(string $code) {
$this->code = $code;
}
}
class PhpVersion {
public private(set) string $version = '8.4';
}
echo (new Country('br'))->code, PHP_EOL; // BR
$v = new PhpVersion();
echo $v->version, PHP_EOL; // 8.4
$animal = array_find(['dog', 'cat', 'cow'], fn(string $a): bool => str_starts_with($a, 'c'));
var_dump($animal); // string(3) "cat"
PHP 8.5
The PHP 8.5 release announcement (released November 20, 2025) highlights the URI extension, the pipe operator, clone with property changes, the #[\NoDiscard] attribute, and the new array_first() and array_last() functions.
The pipe operator and clone with
The pipe operator |> passes the value on its left into the callable on its right, so transformations read from top to bottom. This example comes from the release announcement:
<?php
$title = ' PHP 8.5 Released ';
$slug = $title
|> trim(...)
|> (fn($str) => str_replace(' ', '-', $str))
|> (fn($str) => str_replace('.', '', $str))
|> strtolower(...);
var_dump($slug); // string(15) "php-85-released"
clone now accepts an array of property changes, which makes "with-er" methods on readonly classes much simpler:
<?php
readonly class Color {
public function __construct(
public int $red,
public int $green,
public int $blue,
public int $alpha = 255,
) {}
public function withAlpha(int $alpha): self {
return clone($this, ['alpha' => $alpha]);
}
}
$transparentBlue = (new Color(79, 91, 147))->withAlpha(128);
echo $transparentBlue->alpha, PHP_EOL; // 128
These two examples need PHP 8.5, so select 8.5 in the sandbox before running them.
Try it now
You don't need to install PHP, XAMPP or Docker. Open the WebFiddle PHP sandbox, paste an example, choose a PHP version from the selector (8.0 to 8.5) and click Run. Switching to an older version is a quick way to see which release introduced a feature. To learn how the sandbox runs PHP in your browser, read PHP in WebAssembly vs server-side PHP.
Frequently asked questions
What are the biggest new features in PHP 8.0?
PHP 8.0's release announcement highlights named arguments, attributes, constructor property promotion, union types, the match expression, the nullsafe operator and a Just-In-Time compiler. It also made string-to-number comparisons saner and made internal functions throw consistent type errors, which together make PHP code stricter and easier to reason about than in PHP 7.
What is new in PHP 8.4?
PHP 8.4 introduced property hooks, which attach get and set logic directly to properties, and asymmetric visibility, such as public private(set), to allow public reads but private writes. It also added the Deprecated attribute, HTML5 support in the DOM extension, an object API for BCMath and helpers such as array_find.
What does the pipe operator do in PHP 8.5?
The pipe operator, written as |>, takes the value on its left and passes it as the argument to the callable on its right, returning the result. Chaining several pipes lets you write a sequence of transformations top to bottom, instead of deeply nested function calls that must be read from the inside out.
Is PHP 8's JIT compiler faster for WordPress sites?
The JIT compiler mainly speeds up CPU-intensive code, such as numeric calculations or long-running processing. Typical WordPress or Laravel requests spend much of their time on database queries, file access and network I/O, which JIT doesn't accelerate. Benchmark your own application before assuming a large improvement from enabling JIT.
Can I test different PHP 8 versions online?
Yes. The WebFiddle PHP sandbox runs PHP in your browser through WebAssembly and has a version selector covering PHP 8.0, 8.1, 8.2, 8.3, 8.4 and 8.5. Paste your code, choose a version and run it, then switch versions to compare behaviour or check when a feature was introduced.
WebFiddle