New PHP errors messages in PHP 8.3
The upcoming PHP 8.3 is bringing some new errors messages. They originate from new features, deprecated ones, and extra checks on the source code. Let’s review the new PHP error messages in PHP 8.3 and get our code ready for November 2023.
Previous review
Evolution of error message counts
With distinct 783 error messages, PHP 8.3 is ranking number 4, bumping PHP 8.2 down one notch, and still far behind PHP 7.4 with its 824 distinct error messages. It is also more than PHP 8.2.
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.3 adds 38 new error messages, and removes 11 of them, for a net increase of 27.
Quick disclaimer : the error messages are read from PHP code source, which is in C. In the messages, the %s
is the placeholder for strings, just like with sprintf() in PHP. They usually carry a name, which is dynamically filled by PHP.
Here are the most interesting new PHP error messages.
Calling get_class() without arguments is deprecated
Calling get_parent_class() without arguments is deprecated
Calling get_class() without arguments was only allowed when called from within a class. Then, it would use the current class as the default, and returns its name.
In PHP 8.3, get_class() and get_parent_class()’s arguments are now compulsory. It must be provided as argument. This means using $this
when inside a class.
Another option is to call get_called_class(), which acts as get_class() without arguments. get_called_class() also works with static methods, a.k.a. methods without access to $this
. There is no such thing as get_called_parent_class() or get_called_class_parent() (sic).
<?php class A { public function foo() { var_dump(get_class()); var_dump(get_called_class()); } } (new A)->foo(); // PHP Deprecated: Calling get_class() without arguments is deprecated ?>
This is a changed behavior, with deprecation notice. It will be finalized in PHP 9.
Cannot use %s as value for class constant %s::%s of type %s
This error message is linked to the typing of class constants. In PHP 8.3, class constants may be typed. When this happens, the value of the constant must be of the assigned type.
Of course, there are a wide range of possible error messages, depending on types.
<?php class x { const int A = true; //Cannot use bool as value for class constant x::A of type int } ?>
This is a linted error.
Class constant %s::%s cannot have type %s
Another aspect of class constant typing is that not all types are possible.
Obviously, common types like int
, float
, array
, bool
, true
, false
, null
, object
, any class, and any valid combinaison of those with union, intersection or DNF.
<?php class x { // typing is a bit superfluous, yet valid const int|string|bool A = true; // a constant with different types // it will depend on configuration const ?string B = PHP_MAJOR_VERSION >= 8 ? 'OK' : null; } ?>
On the other hand, some specific types are not possible: never
, void
, callable
. The two first are quite obvious, while callable
is forbidden to avoid confusing situations with actual method calls.
<?php class x { const never GIVE = 'you up'; } ?>
This is a linted error.
Cannot use the %s modifier on a %s
Here, modifiers are options for class elements, such as abstract
, static
, public
, final
, etc. The class elements are properties, methods and class constants.
When such elements get the wrong modifier, PHP used to emit a syntax error. Although this was simple to understand, the new error messages are now a lot more expressive.
<?php class Test { public function __construct(public static $x) {} //Cannot use the static modifier on a promoted property } ?>
This is a lint error.
Cannot use the abstract modifier on an anonymous class
Cannot use the final modifier on an abstract method
Cannot use the final modifier on an anonymous class
Those are specific errors, related to anonymous classes. Anonynous classes can’t be abstract as they won’t be derived. They also cannot hold abstract methods for the same reason.
Anonymous classes are always final by default, as they can’t be derived. Even though, this message is an actual upgrade from a previous syntax error.
<?php $x = new final class() {}; ?>
This is a linted error.
Increment on non-alphanumeric string is deprecated
One of the open secrets of PHP is using the increment operator on strings. It actually increments strings to its next ASCII value, or it adds one to its value.
<?php $x = 'a'; $x++; echo $x; // b $z = 'z'; $z++; echo $z; // aa ?>
Knowing that, the error message above looks like the death warrant of this feature. In fact, the reality is quite subtle. For starter, the above examples are still valid.
Then, PHP still goes a long way to keep the feature working, by detecting numbers or valid incrementable strings, before reporting an error.
Here is a selection of cases, sourced from the unit tests of PHP 8.3. It includes integers, floats, negative numbers, several types of strings:
--- testing: '0' --- int(1) --- testing: '65' --- int(66) --- testing: '-44' --- int(-43) --- testing: '1.2' --- float(2.2) --- testing: '-7.7' --- float(-6.7) --- testing: 'abc' --- string(3) "abd" --- testing: '123abc' --- string(6) "123abd" --- testing: '123e5' --- float(12300001) --- testing: '123e5xyz' --- string(8) "123e5xza" --- testing: ' 123abc' --- Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d string(7) " 123abd"
Most of the previous behaviors have been preserved. The last one, which generates the error, has a string which is not obvious to convert, because of the initial space. Multi bytes strings might also have the same behavior.
To prepare for the future, such feature should be replaced by the dedicated str_increment() and str_decrement() functions, which handle these situations. They will stay compatible with future versions.
There are more details about the evolution of this feature in the RFC below.
This is an execution error.
Decrement on empty string is deprecated as non-numeric
Decrement on non-numeric string has no effect and is deprecated
Decrement on type bool has no effect, this will change in the next major version of PHP
Decrement on type null has no effect, this will change in the next major version of PHP
Specific error messages are introduced for the decrement operator. It already had no effect on strings nor boolean, and now, it is mentionned in the errors.
Increment on type bool has no effect, this will change in the next major version of PHP
If you have ever tried to apply the increment or decrement operator on boolean values, you may have noticed that it doesn’t have any effect.
Well, PHP 8.3 introduce a specific warning, that tells it to anyone who tries. The behavior is unchanged since PHP 7.0, but now, it is clearly stated.
<?php $a = true; $a++; var_dump($a); $b = true; $b--; var_dump($b); ?>
This is an execution error.
Duplicate declaration of static variable $%s
The variable used in the use
clause of a closure represents a variable which is coming from the creating context. On the other hand, the closure may also declare a static variable (not a property), with the same name. That leads to confusion for the human and the developer alike.
Now, this is reported at linting time.
<?php $a = null; function () use (&$a) { static $a; }; ?>
This is a lint error.
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.
Maximum call stack size of %zu bytes reached during compilation. Try splitting expression
Throwing resource destructor called
cannot cancel the query: %s
.
Get ready for PHP 8.3
Hopefully, this quick tour in the new error messages of PHP 8.3 will help preparing the code for its own migration to PHP 8.3.
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.3 ruleset, with rules dedicated to PHP 8.3. They can run on PHP 8.2, so as to be ready for November 2023.
Happy auditing.