New PHP errors messages in PHP 8.2
The upcoming PHP 8.2 is bringing some new errors messages, either from new features, or from extra checks on the source code. Let’s review their numbers, and some of the extra checking that will help us.
Evolution of error message counts
With distinct 751 error messages, PHP 8.2 is only ranking number 4, quite far behing PHP 7.4 with its 824 error messages.
Usually, the distinct number of error messages grow within a PHP major version, as deprecations are accumulated until the next breaking change version : at that point, they are removed and the whole number drops significantly. We’ll see what happens with PHP 9.0.
New error messages
PHP 8.2 adds 22 new error messages, and removes 13 of them, for a net increase of 9.
Quick disclaimer : the error messages are read from PHP code source, which is in C. The %s
is the place holder for strings, just like with sprintf() in PHP. They usually carry a name, which is dynamically filled by PHP.
Here are the new PHP errors.
Callables of the form [“Foo”, “parent::bar”] are deprecated
Several syntaxes used to defined callables are deprecated in PHP 8.2. This is one of them, and there are several variations, with parent
, static
, self
or the class name.
<?php class Foo { public static function bar() { echo __METHOD__; } } class FooFoo extends Foo { public function test() { call_user_func(array('FooFoo', 'parent::bar')); } } (new foofoo)->test(); ?>
Cannot apply #[AllowDynamicProperties] to interface
Cannot apply #[AllowDynamicProperties] to readonly class %s
Cannot apply #[AllowDynamicProperties] to trait
The deprecation of the (wanted or not) dynamic properties is going to be a big hit with PHP 8.2 : ambiguity intended.
The AllowDynamicProperties
attribute is introduced to deflect that problem. Applied to classes, it allows the dynamic properties that are now, by default, forbidden.
Yet, this is a class-only attribute, so it is not possible to put it on trait (for example), and spread it across the code source. Class only.
<?php #[AllowDynamicProperties] trait t {} ?>
Also, linted before execution.
Creation of dynamic property x::$y
is deprecated
Deprecation message, for execution time.
<?php class x {} $x = new x; $x->y = 1; ?>
Type contains both true and false, bool should be used instead
PHP 8.2 introduces the type true
, as a complement to the type false
. It is now possible to type true
a method that only returns true
or a property that only holds true
(and nothing else).
This error message detects that true
and false
are used at the same time, and they should actually be merged in bool
.
<?php class x { private true|false $bool; } ?>
In PHP 8.1 and older, true
is confused with a class, and gets its own error message : Cannot use 'true' as class name as it is reserved
.
Using ${expr}
(variable variables) in strings is deprecated, use {${expr}}
instead
Using ${var}
in strings is deprecated, use {$var}
instead
Two error messages dedicated to the deprecation of the ${}
operator. It used to be a very clever way to make variable variables, and it was also mostly unused.
<?php $a = "c"; $cd = 1995; echo "${ $a . 'd' }"; ?>
This should be very rare, as the number of occurrences are below 20 over 2000 PHP projects.
iterable type is now a compile time alias for array|Traversable
As detailled in the UPGRADING document, iterable is now a built-in type, and it is replaced on the fly by array
and Traversable
. This changes the old error messages, but not the behavior of PHP.
Also, iterable unioned with other types will simply extends the list of types availables.
<?php function foo(iterable|C $a) {} foo(3); ?>
As for intersectional types, which would use iterable
to not be pure types, it is already monitored by PHP with Type iterable cannot be part of an intersection type
.
null cannot be marked as nullable
Well, what else to say ? Someone has to try it : we did. It works as expected.
<?php class x { private ?null $a; } ?>
%s class %s cannot extend %s class %s
Usually the %s
is a placeholder for a name. And, in this very case, it is for a property : readonly classes can’t be extended by non-readonly classes.
Readonly classes are new in PHP 8.2 : they are an extension of the readonly properties, available in PHP 8.1. The option covers a whole class, and each of its property are now readonly, without extra specification, like for final.
<?php readonly class Foo { } class Bar extends Foo { } ?>
This is detected at compilation time, when the classes are in the right order (like here). When they are in the reverse order, or split across multiple files, this appears at execution time.
%s::__toString() implemented without string return type
This error looks like a twin of Bar::__toString(): Return type must be string when declared
. Yet, we could not reproduce it. Anyone with that ‘luck’ ?
<?php class Bar { function __toString() : int {} } ?>
Updated error messages
The updated error messages are usually rewriting of previous ones. We would say refactored.
%s %s cannot implement previously implemented interface %s
<?php class x implements i, i, i {} ?>
This one is easy to spot, including when use
command is at work. The error message appears after Interface "i" not found
(here), and only at execution time.
Also, this is not checked across classes, within a class family. For this, there is Already Parent Interface.
%s %s inherits both %s::%s and %s::%s
This error messages happens when a constant is defined both in an interface and in a class. This is a conflict, even when the value of the constant is the same. Unlike trait, there are no way arbitrage this conflict, and it leads to a fatal error.
<?php class C { const C = 1; } interface I { const C = 1; } class C2 extends C implements I { } ?>
%s %s must implement interface %s as part of either %s or %s
Traversable cannot be implemented directly, but only through Iterator or IteratorAggregate. Traversable is the only class that has this behavior.
<?php class Foo implements Traversable { } ?>
Unknown errors
Here are some errors which are in the source code of PHP, but we could not reproduce. If you have experience, you can share it with us.
%s %s could not implement interface %s
Cannot end an oplog without starting it
: oplog is for Operation Log.huge_pages: thp unsupported on this platform
.
Get ready for PHP 8.2
Hopefully, this quick tour in the new error messages of PHP 8.2 will help preparing the code for its own migration to PHP 8.2.
Since some of the checks are only available at execution time, it is worth running static analysis on it to spot potential errors. Exakat include the Compatibility PHP 8.2 ruleset, with rules dedicated to PHP 8.2. They can run on PHP 8.1, so as to be ready for November 2022.
In the mean time, we’ll keep an eye on the upcoming feature freeze.
Happy auditing.