WIndow onto PHP 8.2New 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();

?>

RFC

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.

RFC

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.

RFC

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.

RFC

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.

RFC

%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.