With PHP 8.2’s release date, November 24 this year, drawing ever closer, let’s have a look at some of the key changes that you can expect to see.
Deprecation of Dynamic Properties
In PHP 8.2, setting dynamic class properties is deprecated.
There are a number of motivations behind this change, but the key ones are to:
Be explicit when using dynamic properties
Prevent mistakes associated withthem.
This change should make code easier to maintain and easier for static analyzers to introspect. Have a look at the following code, which attempts to set the dynamic property city on the User class.
php
class User
{
public string $firstName;
public function __construct(string $firstName)
{
$this->firstName = $firstName;
}
}
$user = new User("Matthew");
$user->city = "Nuremberg";
When run, the following deprecation notice would be issued.
php
// Fatal error: Uncaught Error: Cannot create dynamic property User::$city
If dynamic properties are desired or required, such as for backwards-compatibility, a class can be marked with the new #[AllowDynamicProperties] attribute, introduced in the RFC, as in the following example.
php
#[AllowDynamicProperties]
class User
{
public string $firstName;
public function __construct(string $firstName)
{
$this->firstName = $firstName;
}
}
It’s worth noting that PHP’s magic get and set methods can still be used after this change.
PHP 8.2 Readonly Classes
PHP 8.1 introduced readonly properties, which allows class properties to be initialized once, but not to be changed afterward. PHP 8.2 takes this further by allowing whole classes to be marked readonly, as in the example below.
php
readonly class User {
public string $firstName;
public string $lastName;
public string $emailAddress;
public function __construct(
string $firstName,
string $lastName,
string $emailAddress
) {
$this->firstName = $firstName;
$this->lastName = $lastName;
$this->emailAddress = $emailAddress;
}
}
When a class is marked readonly', all of its properties are marked readonly`, avoiding the need to mark each one individually.
However, before you get too excited, it’s worth knowing the limitations of this functionality. These are:
Dynamic, untyped, and static properties are not allowed.
The #[AllowDynamicProperties] attribute cannot be used, otherwise a Fatal error similar to Fatal error: Cannot apply #[AllowDynamicProperties] to readonly class will be thrown.
A readonly class can only extend a readonly parent class.
Regardless of these limitations, this change should be a very welcome one for developers who appreciate the benefits of immutability.
PHP 8.2 New no-capture modifier
A new /n or No-capture modifier for the preg_* functions
This is another exciting change – if you’re a fan of regular expressions (or regexes). Before I dive into it, take a look at the example below.
php
$regex = '/(\(\d\)\d{3})-(\d{4})-(\d{4})/';
$number = '(0)123-4567-8901';
preg_match($regex, $number, $matches);
var_dump($matches);
The expression in $regex uses capturing groups. These allow the regular expression to be broken up into sub-expressions. In this case, the sub-expressions match the three parts of a standard German phone number, stored in $number.
If you ran the code, the variable $matches would contain an array with an entry for the entire phone number, along with one for each of the three parts of the phone number, without the separating hyphens. In this case:
php
array(5) {
[0]=>
string(16) "(0)123-4567-8901"
[1]=>
string(6) "(0)123"
[2]=>
string(4) "4567"
[3]=>
string(4) "8901"
}
However, you may not be interested in each of the three components. Perhaps only the first and last. So, to skip the second one you’d mark it as a non-capturing group, by prefixing it with ?:, as in the following example.
php
$regex = "/(\(\d\)\d{3})-(?:\d{4})-(\d{4})/"
Then, the script would output the following:
php
array(5) {
[0]=>
string(16) "(0)123-4567-8901"
["prefix"]=>
string(6) "(0)123"
[1]=>
string(6) "(0)123"
["area_code"]=>
string(4) "8901"
[2]=>
string(4) "8901"
}
Marking sub-expressions you’re not interested in this way is fine, until you want to disable all capturing groups, save a small handful, in larger, more complex regular expressions. The new /n modifier helps make that a lot easier, by disabling all capturing groups unless they’re named.
Named capturing groups work just like capturing groups, except that the array storing the matches also has a string key for every match. Take the following example.
php
$regex = "/(?P<prefix>\(\d\)\d{3})-(?P<local_code>\d{4})-(?P<area_code>\d{4})/";
preg_match($regex, '(0)123-4567-8901', $matches);
var_dump($matches);
Here, the first sub-expression is named “prefix”, the second “local_code”, and the third “area_code”. When run, the script will output the following:
array(7) {
[0]=>
string(16) "(0)123-4567-8901"
["prefix"]=>
string(6) "(0)123"
[1]=>
string(6) "(0)123"
["local_code"]=>
string(4) "4567"
[2]=>
string(4) "4567"
["area_code"]=>
string(4) "8901"
[3]=>
string(4) "8901"
}
Now, if you only want the middle sub-expression (“local_code”), don’t name the other two sub-expressions and use the new \n modifier, as in the following example.
$regex = "/(\(\d\)\d{3})-(?P<area_code>\d{4})-(\d{4})/n";
Then, the $matches array will only have a match for the entire expression, plus the one, named sub-expression (with a numeric and string key).








