Readonly Classes in PHP 8.2
PHP 8.2 introduces readonly classes, which are a natural extension of the readonly property modifier added in PHP 8.1. When you declare a class as readonly, every property within that class automatically becomes readonly without needing individual declarations. The class also cannot be cloned, which prevents any accidental duplication of its state.
readonly class User {
public function __construct(
public string $name,
public string $email,
public DateTimeImmutable $createdAt
) {}
}
The readonly class syntax removes a significant amount of boilerplate. In PHP 8.1, you would have needed to declare each property as readonly individually and add a private constructor with manual property assignment. Readonly classes work well for value objects, data transfer objects, and any class whose state should remain fixed after construction.
The key benefit for business web applications is predictable behaviour. When an object cannot be modified after creation, debugging becomes easier because you can trace exactly where data originates and changes. This is particularly valuable in applications that process sensitive data or maintain complex state transitions.
Constants in Traits
Before PHP 8.2, traits could not define constants. If you wanted shared constant values across classes using a trait, you had to define those constants in each class or use an interface as a workaround. This led to duplication and maintenance headaches.
PHP 8.2 removes that limitation. Traits can now define constants that become available to any class using the trait. This enables cleaner code organisation and removes the need for boilerplate constant definitions.
trait TimestampedTrait {
public const UPDATED_AT = 'updated_at';
public const CREATED_AT = 'created_at';
private ?DateTimeImmutable $timestamp = null;
public function touch(): void {
$this->timestamp = new DateTimeImmutable();
}
}
class Article {
use TimestampedTrait;
public function __construct(
public readonly string $title
) {
// Article can use self::CREATED_AT and self::UPDATED_AT
}
}
This pattern is particularly useful for framework-style code where multiple models share common constants. Rather than defining the same constant in every model class, you define it once in the trait and every class that uses the trait inherits it automatically.
The constants follow normal PHP visibility rules. A public constant is accessible everywhere, while protected or private constants restrict access to the trait or its immediate class context.
Disjunctive Normal Form Types
DNF types allow you to combine union and intersection types using a specific syntax. In practical terms, this means you can express that a parameter must be either a specific class that implements multiple interfaces, or null.
// A parameter that is either a CacheItem that is also Serializable, or null
function storeCache(CacheItem&Serializable|null $item): void {
if ($item === null) {
return;
}
// $item is guaranteed to be CacheItem and Serializable here
}
The syntax follows a clear pattern: intersection types are grouped together first, then unioned with other types. This formalises what developers were already doing with multiple separate type declarations and makes the type system more expressive.
DNF types help catch bugs at compile time rather than runtime. When your function signature declares exactly what it accepts, static analysers and IDEs can provide better warnings about type mismatches before your code runs.
Removal of Dynamic Properties
PHP 8.2 deprecates dynamic properties, which were a source of subtle bugs in PHP applications. A dynamic property is created when you assign a value to a property that has not been declared in the class. PHP would silently create the property rather than throwing an error.
class User {
public string $name;
}
$user = new User();
$user->name = 'Alice';
$user->naem = 'Bob'; // Typo - creates a new property instead of erroring
This silent behaviour made typos in property names difficult to track down. The deprecation notice in PHP 8.2 warns you when dynamic properties are used, and PHP 9.0 will throw an Error instead of silently accepting them.
If your codebase relies on dynamic properties, you have two paths forward. The first is to add the #[AllowDynamicProperties] attribute to the class to silence the deprecation warning while you refactor. This is necessary for proxy classes generated by some ORM frameworks. The second path is to declare all properties explicitly and update any code that relies on dynamic property creation.
Performance Improvements in PHP 8.2
PHP 8.2 continues the performance trajectory started with PHP 8.0 and its JIT compiler. The renewed focus on JIT optimisation in PHP 8.2 delivers measurable improvements for typical workloads.
On Laravel and WordPress applications, enabling the JIT compiler typically yields 5 to 15 percent more request throughput compared to PHP 8.1. The improvement is most noticeable in CPU-bound operations such as string manipulation, encryption routines, and image processing tasks. For I/O-bound operations where the bottleneck is database queries or external API calls, the gains are smaller because the PHP engine is waiting on external services for most of the request time.
Enable the JIT compiler in your php.ini configuration. For web applications serving many short requests, use jit=function. For long-running CLI scripts that execute the same code repeatedly, jit=tracing provides better performance because it traces code execution paths and optimises frequently used routines.
Deprecated Functions to Address Before Upgrading
PHP 8.2 deprecates several functions that have been in the language for years. These will be removed in PHP 9.0, so you should address them before upgrading.
- mysql_* functions: These old MySQL functions have been discouraged for years. Migrate to PDO or mysqli with prepared statements.
- utf8_encode and utf8_decode: These functions handle only Latin-1 character conversion. Use mb_convert_encoding for proper Unicode handling.
- ${ } string interpolation: The complex variable syntax using curly braces around variable names is deprecated. Use explicit string concatenation or explicit variable parsing.
- count() on non-countable types: PHP 8.2 is stricter about passing non-countable values to count(). Your code may have been silently accepting this before.
Run your test suite with PHP 8.2 and watch for deprecation warnings. Addressing these warnings before they become errors prevents unexpected failures when PHP 9.0 is released.
Practical Upgrade Checklist
Upgrading to PHP 8.2 requires careful preparation, particularly for business applications where downtime has real costs.
- Test in development first: Run your complete test suite against PHP 8.2. This catches most compatibility issues before they reach production.
- Check framework compatibility: Ensure your framework version supports PHP 8.2. Laravel 10 and Symfony 6.2 both support PHP 8.2. Older versions may require upgrades first.
- Review dependencies: Verify that your Composer dependencies are compatible. Run
composer update --dry-runto see what would change without actually applying updates. - Address deprecation warnings: Run your application with
php -d error_reporting=E_ALLto surface all warnings. Each deprecation warning represents code that will break in PHP 9.0. - Test in staging: Deploy to a staging environment that mirrors production before updating production servers. Monitor logs for any issues that did not appear in testing.
- Plan rollback: Have a rollback plan ready. Know how to switch back to the previous PHP version if issues appear after deployment.
How PHP 8.2 Compares to Earlier Versions
PHP 8.0 introduced the JIT compiler and named arguments. PHP 8.1 added readonly properties, enums, and fibers for asynchronous programming. PHP 8.2 builds on this foundation with readonly classes, constants in traits, and DNF types that make the type system more expressive.
For developers maintaining older codebases, the PHP 7.4 features overview shows how much the language has evolved. Typed properties and arrow functions, which seemed advanced in PHP 7.4, are now basic building blocks. The improvements in each version make PHP more suitable for large-scale application development where type safety and predictable behaviour matter.
What Comes After PHP 8.2
PHP 8.3, released in late 2023, builds further on the PHP 8.2 foundation. The tracing JIT compiler received significant improvements that benefit long-running scripts and CLI applications. If you are planning a new project, PHP 8.3 is worth considering, but PHP 8.2 remains a solid choice for applications where stability and ecosystem maturity take priority over the latest features.
The PHP release cycle maintains two years of active support for each minor version. This gives development teams adequate time to upgrade without rushing. For existing applications running PHP 8.1, upgrading to 8.2 is a reasonable near-term step while planning the eventual move to 8.3.
Getting Ready to Upgrade
Upgrading PHP versions is a routine part of maintaining web applications. PHP 8.2 offers meaningful performance improvements and a cleaner type system while maintaining compatibility with most existing code. The deprecated features give you clear guidance on what to fix before PHP 9.0 arrives.
If you need help reviewing your current codebase before upgrading, prepare details about your PHP version, framework version, and any deprecation warnings you have already seen. A technical review can identify the scope of changes needed and potential risks before you begin the upgrade process.