PHP 8 is not just a minor upgrade; it marks a paradigm shift in the language's evolution. From PHP 8.0 to 8.4, each release has introduced features that fundamentally change how applications are designed: Enums for expressive domain models, readonly properties for declarative immutability, match as an elegant alternative to switch, Fibers for lightweight concurrency, and the latest innovations such as Property Hooks and Typed Class Constants. This pillar guide covers the entire landscape of modern PHP 8 features, providing the foundation to leverage them effectively in real projects, while pointing to dedicated deep dives for each topic.
PHP 8 Version Evolution: From 8.0 to 8.4
Each PHP 8 version addresses historical limitations. PHP 8.0 introduced named arguments, attributes, and the match expression, eliminating reliance on complex reflection. PHP 8.1 added Enums, readonly properties, and Fibers. PHP 8.2 brought true type and readonly classes, while PHP 8.3 and 8.4 refined the experience with typed class constants, json_validate, and property hooks. Understanding this evolution helps you decide the minimum viable PHP version for your project.
Readonly Properties, Enums, and Match Expression
These three features, introduced between 8.0 and 8.2, form the core of modern PHP writing. Proper use eliminates entire categories of bugs and makes code self-documenting.
Readonly Properties and Readonly Classes
Readonly properties (since PHP 8.1) ensure a class property can be set only once, typically in the constructor. PHP 8.2 extended this with readonly classes, which implicitly make all instance properties read-only. This is essential for implementing immutable Value Objects and DTOs without manual getters.
readonly class UserDTO {
public function __construct(
public string $name,
public string $email,
) {}
}
$user = new UserDTO('Mario', 'mario@example.com');
// $user->name = 'Luigi'; // Error: cannot modify readonly property
Enums: Type Power and Methods
PHP 8.1 Enums are far more than simple constant sets. They can contain methods, implement interfaces, and even define backed cases with native scalar values. This allows modeling finite states without resorting to strings or arrays.
enum Status: string {
case Pending = 'pending';
case Active = 'active';
case Inactive = 'inactive';
public function label(): string {
return match($this) {
self::Pending => 'Pending',
self::Active => 'Active',
self::Inactive => 'Inactive',
};
}
}
Match Expression: an Enhanced Switch
The match expression (PHP 8.0) replaces switch with safer, more flexible syntax: no break required, it implicitly returns a value, and uses strict === comparison. It is especially useful for mapping, routing, and linear business logic.
$result = match($status) {
Status::Pending => 'Awaiting processing',
Status::Active => 'Running',
Status::Inactive => 'Closed',
default => 'Unknown',
};
New in PHP 8.3 and 8.4: Typed Class Constants, Property Hooks, and json_validate
Versions 8.3 and 8.4 introduced features that improve type safety and code readability, revolutionizing property and constant management.
Typed Class Constants (PHP 8.3)
Before PHP 8.3, class constants could not be explicitly typed; the type was inferred from the value. Now you can declare a type for constants, preventing future assignment errors (e.g., in inheritance).
class PaymentGateway {
final public const string VERSION = '3.0';
// Cannot be overridden with a different type
}
Property Hooks (PHP 8.4)
Property Hooks represent the biggest innovation in property management in years. They allow defining get, set, and transformations directly on the property declaration, without separate getter/setter methods. This merges the simplicity of public properties with the power of accessor methods.
class User {
public string $name {
get => $this->name;
set => trim($value);
}
}
Property hooks also support separate body implementations, visibility changes (public get, private set), and access to backing storage via backed properties.
json_validate (PHP 8.3)
The json_validate function checks if a string is valid JSON without fully decoding it. It is much more efficient than json_decode when only validity is needed, returning a boolean.
if (json_validate($payload)) {
// proceed with decoding
$data = json_decode($payload, true);
} else {
throw new InvalidArgumentException('Invalid JSON');
}
Fibers, Promises, and Async Programming in PHP 8.1+
With the introduction of Fibers in PHP 8.1, the language gained the ability to run non-preemptive coroutines. Fibers allow writing asynchronous code that looks synchronous, without relying on third-party libraries or separate processes. Although not true concurrency (single-threaded), they enable controlled suspension and resumption, ideal for I/O-bound operations.
Fiber: Basic Mechanism
A Fiber is an execution unit that can be suspended via Fiber::suspend() and resumed with ->resume(). The programmer manually manages control passing, often combined with an event loop.
$fiber = new Fiber(function (): void {
$value = Fiber::suspend('first suspend');
echo "Resumed with: $value";
});
$result = $fiber->start();
echo $result; // 'first suspend'
$fiber->resume('hello'); // prints 'Resumed with: hello'
Promises and Async/Await
Promises are not native in PHP, but can be implemented on top of Fibers using libraries like Amp or ReactPHP. The combination of Fibers and Promises enables async code with await reminiscent of JavaScript. For example, using amphp/amp and amphp/http-client:
\Amp\async(function () {
$response = await \Amp\Http\Client\request('https://api.example.com');
$body = await $response->getBody()->buffer();
echo $body;
});
This approach is ideal for applications that need to handle multiple parallel HTTP requests or database accesses without blocking the main thread. However, for simple scenarios, job queues with Redis or RabbitMQ often suffice.
Best Practices for Migrating from PHP 7 to PHP 8
Migrating from PHP 7 to PHP 8 requires attention to breaking changes such as removal of deprecated functions (e.g., each, create_function), changes in behavior of compact and gettype, and introduction of strict types. Key steps include:
- Upgrade to PHP 7.4 first to leverage intermediate features (arrow functions, typed properties).
- Gradually enable
declare(strict_types=1)to reduce implicit type errors. - Replace
is_numericandis_stringwith more specific type checks. - Employ static analysis tools like PHPStan or Psalm to identify incompatibilities.
- Remove
func_get_argsandfunc_num_argsin favor of variadic arguments with types. - Adopt match and Enums after assessing refactoring cost.
Conclusion and Next Steps
PHP 8 has transformed the language into a modern environment, competitive with other languages for structured and asynchronous programming. The features illustrated here represent only the surface; each component deserves a dedicated deep dive, like those available in this content cluster. For a detailed analysis of PHP 8.3 and 8.4 with practical examples, see the article PHP 8.3 and 8.4 New Features. For comprehensive coverage of PHP application vulnerability management, read the OWASP Top 10 2025. Finally, to see how PHP 8 is applied in modern frameworks, explore Laravel 12. The path is clear: start writing PHP like a programmer of the future.
Sponsored Protocol