Common PHP 8.0 Compilation Error Messages

With PHP 8.0 closing on us, it is high time to check our code bases to see if they compile, at least. Here is a list of common PHP 8.0 error messages, and what do to with them.

The errors have been found on a corpus of 1756 PHP projects. Any emitted error was compared to the result of the PHP 7.4 compilation. This means that those errors are fatal in PHP 8, while they were absent, or a warning in PHP 7.4. In both cases, in PHP 7.4, it used to be possible to brush them under the carpet, but not in PHP 8.0 anymore.

Common PHP 8.0 compilation errors

  • Array and string offset access syntax with curly braces is no longer supported
  • Unparenthesized a ? b : c ? d : e is not supported. Use either (a ? b : c) ? d : e or a ? b : (c ? d : e)
  • __autoload() is no longer supported, use spl_autoload_register() instead
  • Cannot use ‘parent’ when current class scope has no parent
  • syntax error, unexpected ‘match’
  • The (real) cast has been removed, use (float) instead
  • The (unset) cast is no longer supported
  • Declaration of A2::B($c, $d = 0) must be compatible with A1::B(&$c, $d = 0)
  • Unterminated comment starting line

Array and string offset access syntax with curly braces is no longer supported

Array and string offset access syntax with curly braces is no longer supportedmeans that only the square bracket syntax is now valid.

 
<?php 
   $array = range(0, 10); 
  echo $array{3}; // 4 
?> 

Replace the { with [, and the code will be good again. Exakat spots those with the rule No more curly arrays.

Unparenthesized a ? b : c ? d : e is not supported. Use either (a ? b : c) ? d : e or a ? b : (c ? d : e)

Introduced in PHP 7.4, it is not possible to nest ternary operators. This is related to ternary being right associative, while most of the operators are left associative. PHP RFC: Deprecate left-associative ternary operators.

 
<?php 
1 ? 2 : 3 ? 4 : 5; // deprecated 
(1 ? 2 : 3) ? 4 : 5; // ok 
1 ? 2 : (3 ? 4 : 5); // ok 
?> 

The error message is quite verbose : take advantage of it! Add some parenthesis, or even , split the nested operation into independent expressions. Exakat spots those with the rule Nested Ternary Without Parenthesis.

__autoload() is no longer supported, use splautoloadregister() instead

This error message might appear here thanks to very old applications. Or if they try to support very old PHP versions. In any case, the message is self-explanatory.

Cannot use ‘parent’ when current class scope has no parent

Using the parent keyword in a class without parent, a.k.a. without extends keyword, used to be a Deprecation Notice. In fact, the class would blow up during execution with a ‘Cannot access parent:: when current class scope has no parent’ Fatal error.

It is now a Fatal error at linting time. This will shorten significantly the time between the bug creation and its discovery.

 <?php 
class x { 
   function foo() { 
      echo parent::a; 
   } 
}

(new x)->foo(); 
?> 

As for the fix, there are lots of options, depending on how this parent keyword ended up there in the first place. Exakat spots those with the rule Class Without Parent.

syntax error, unexpected ‘match’

This is a consequence of the introduction of the match instruction in PHP. It is not possible to use that name in instantiation (new), use expressions, instanceof, typehints, functions, classes, interfaces, traits or constants. It is still OK inside a namespace, or for a variable name.

 <?php

// This Match is still valid, thanks to the new Qualified Name processing 
use Peridot\Leo\Matcher\Match;

// This Match is invalid 
function foo(Match $match) { 
   // do something 
}

// Match side effect : syntax error, unexpected ',' 
$result = match($content,"'KOD_VERSION','(.*)'");

?>

When match is used as a function name, it may lead to an error about commas : the main argument of the new match keyword only accept one argument, so no comma.

The only solution is to rename the classes, interfaces, traits, functions or constants with another name and update the use expressions accordingly.

The (real) cast has been removed, use (float) instead

All is said here. (real) is gone, long live (float).

 
<?php 
  $price = (real) getActualPrice(); 
?> 

Just replace (real) by (float). While you’re at it, you can replace is_real() by is_float() : is_real() didn’t make it into PHP 8.0. Exakat spots those with the rule Avoid Real.

The (unset) cast is no longer supported

The big brother of the unset function is a type cast (unset). It used to be actually the typecast (null) (not in name, but in usage). Very little new about this, and it is a good thing : it is gone for good.

 
<?php 
   (unset) $foo; 
?> 

Exakat spots those with the rule Cast unset usage.

Declaration of A2::B($c, $d = 0) must be compatible with A1::B(&$c, $d = 0)

Checking for method compatibility used to be a warning in PHP 7, and it is now a Fatal error at linting time. The method signature in a parent and its child class must be compatible. It means a lot of different things, depending on visibility, reference, typehint, default values. It is worth a whole article by itself.

The important part is three folds : first, PHP 8.0 emits a Fatal error at compile time for that. So, your PHP 7.0 may hurt on 8.0. If you can fix it now.

 
<?php 
class A1 { 
   function B(&$c, $d = 0) {} 
}

class A2 extends A1 { 
  function B($c, $d = 0) {} 
}

?> 

The second important part is that it only works when PHP lints both classes (parent and child), in the same file, and in the right order : parent first, child second. Otherwise, PHP will only check the compatibility at execution time, and deliver a Fatal error at the worst moment.

The third important part is that compatibility between method signature doesn’t cover argument names. The following code is valid, and a major sleeping bug. Just notice that the variables have been swapped.

 
<?php 
class A1 { 
   function B($c, $d = 0) {} 
}

class A2 extends A1 { 
   function B($d, $c = 0) {} 
}

?> 

Exakat spots those with the following rules Incompatible Signature Methods, and Swapped arguments.

Unterminated comment starting line

Unterminated comment starting line used to be a warning. It is now a parse error.

 
<?php 
/** I always start, but never finish...

Just close the comment, and the code will be good again.

Compile with PHP 8.0 now!

PHP 8.0 moved a significant number of messages from Notice to Fatal errors, and, more importantly, from the execution phase to linting phase. This means that checking your current code with PHP 8.0 is sufficient to bring light on quirky pieces of code that will raise error when you want to upgrade to PHP 8.0. Simply fixing them will also improve your PHP 7.x code!

In the meantime, linting is as fast as it is superficial : it processes files individually, and postpone until execution some of the checks. Static analysis tools cover those situations, and report very early potential bugs and inconsistencies.

Install exakat and run the Migration audit on your code to get even better prepared for the Great Apparition of PHP 8.0. See you next month!