Skip to the content
Documentation
Help Start
Reading in:
  • German: 9,059 of 9,059 pages
About the help in other languages
All help pages

Writing code that runs on PHP 8.0

The rules for PHP code that must run on PHP 8.0, the stock PHP of RHEL 9 (and, without support, on 7.4 for the kernel) - the syntax you may not use, how lib/phpcompat.php and function_exists() guards work, arguments…

Download as PDF

Address: https://doc.exponential.earth/exphelp/viewer/help/php-developers/writing-code-that-runs-on-php-8-0.md

On this page

Writing code that runs on PHP 8.0

This page is for PHP developers who write kernel code or extensions that ship with Exponential. Every such file must run on PHP 8.0, the stock PHP of RHEL 9, and on 8.5, the newest; the kernel itself is also usable without support on PHP 7.4 from 6.0.15 (Supported PHP versions). The rules are short, and the tools check them, but CI runs PHPUnit only on 8.1 and later: on 8.0 your code is checked by syntax and boot only, so get it right as you write it.

Contents

  1. Syntax you may not use
  2. Functions newer than PHP 8.0
  3. Arguments that later versions added
  4. Defaults that changed: HTML escaping
  5. Checking your code
  6. Examples from the kernel

Syntax you may not use

PHP 8.0 cannot parse these, so one occurrence makes the whole file fail to load:

SyntaxSinceWrite instead
enum Status { ... }8.1class constants
readonly properties and classes8.1, 8.2a private property with a getter
never return type8.1no return type (the kernel style has none anyway)
new in initializers (function f( $x = new Foo() ))8.1$x = null, then $x = $x ?? new Foo()
first-class callables (strlen(...))8.1'strlen' or array( $object, 'method' ) or a closure
intersection types (A&B)8.1no type (see Why the code has no type declarations)
typed class constants8.3an untyped constant

Attributes such as #[\ReturnTypeWillChange] and #[\Override] are harmless on 8.0: PHP 8.0 reads them as attributes and ignores unknown ones.

Functions newer than PHP 8.0

There are two ways, and the kernel uses both:

  1. A function that can be written in PHP with the same result goes into lib/phpcompat.php, inside if ( !function_exists( '...' ) ). autoload.php loads the file only when PHP_VERSION_ID < 80100, so on 8.1 and later it is not even opened and PHP's own function runs. Today it defines array_is_list().

    if ( !function_exists( 'array_is_list' ) )
    {
        function array_is_list( array $array )
        {
            $i = 0;
            foreach ( $array as $key => $unused )
            {
                if ( $key !== $i++ )
                    return false;
            }
            return true;
        }
    }
  2. A function that cannot be written in PHP is called behind function_exists(), with a fallback that is correct on 8.0:

    fflush( $handle );
    if ( function_exists( 'fsync' ) )
        fsync( $handle );

    The kernel does this for fsync() (8.1), memory_reset_peak_usage() (8.2), str_increment() and str_decrement() (8.3) and image functions such as imageavif().

Arguments that later versions added

A function that exists on 8.0 but gained a parameter later throws an ArgumentCountError on 8.0 when you pass it. Branch on PHP_VERSION_ID:

if ( PHP_VERSION_ID >= 80100 )
    fputcsv( $handle, $row, ',', '"', '\\', "\r\n" );
else
{
    // PHP 8.0: no $eol parameter; write the line and fix its ending afterwards
}

This is how kernel/classes/subitems/expsubitemscsvexport.php writes CSV on every version.

Defaults that changed: HTML escaping

PHP 8.1 changed the default flags of htmlspecialchars(), htmlentities(), html_entity_decode() and htmlspecialchars_decode() to ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401. PHP 8.0's default leaves ' unescaped, so a value in a single-quoted HTML attribute would not be safe on 8.0. Always pass the flags explicitly:

$html = htmlspecialchars( $value, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, 'UTF-8' );

The template operator wash and 27 other kernel and extension files pass them since 6.0.15, so every version gives the same output (Escaping output from PHP).

Checking your code

CheckCommandCatches
PHP 8.0 syntax of changed filesmake lint80 (finds the binary as EXP_PHP80, php8.0, php80, or PHP80=/path)parse errors from newer syntax
PHP 8.0 syntax of every filemake lint80-all PHP80=/path/to/php8.0the same, everywhere, as CI's php80 job
PHPCompatibilitymake phpcs (testVersion 8.0- in phpcs.xml.dist)newer functions and arguments, removed and deprecated functions
Boot on 8.0php bin/php/ezexec.php tests/bin/bootsmoke.php with PHP 8.0a class that cannot load
Install on 8.0composer install --no-dev --prefer-dist with PHP 8.0, in a clean checkouta dependency whose minimum is too high

bootsmoke.php loads the classes of autoload/ezp_kernel.php and the extension map (leaving out the command, view and cronjob classes and the tests, whose syntax is linted instead), so a fatal error at class load time, such as a method signature that no longer matches its parent, shows up even without a test that uses the class.

Examples from the kernel

The 6.0.15 work found these, and the same mistakes are common in extensions (PHP 8.0 support):

MistakeEffect on PHP 8Fix
implode( $pieces, $glue )TypeError since 8.0implode( $glue, $pieces )
crypt() without a saltArgumentCountError since 8.0a random value from random_bytes()
a by-reference parameter where the parent's is by valuefatal error when the class loadsmatch the parent's signature
a subclass method with fewer parameters than the parent'sfatal error when the class loadsadd the parameters
each(), split(), create_function()removedforeach, explode(), a closure (phpcs.xml.dist forbids them)

Become an Exponential Partner

Partners share their information, provide funding, contribute back and develop the products with us, and that is how Exponential grows. A partner website and dashboard are planned for mid-2027: please become a partner today to speed up our growth rate and land new features faster.

Something wrong on this page? Report an error

Documentation license

This documentation is free documentation, licensed under the GNU Free Documentation License 1.3 or later.

Exponential Copyright © 1998-2026 Exponential Foundation and 7x