PHP 8 - New Features, Improvements and Potential Problems with WordPress

Marten Gülink Last updated 11.01.2021
10 Min.
php 8 major update
Last updated 11.01.2021


PHP 8 is here! The major update was released on November 26th, 2020 and introduces an array of new features and some fundamental changes. RAIDBOXES developer Marten explains when PHP 8 can lead to better performance and whether or not WordPress users should be updating to the newest version. 

Introduction to PHP 8 

PHP 8 was first introduced to its alpha testers on June 18, 2020 and has been in a feature freeze since July. So no new additions were allowed to be added until the release on November 26. A unique feature of this release is that we are skipping PHP 7.5 and going straight to PHP 8. And this jump comes with a lot of features. 

One of the most common questions about PHP 8 that WordPress users probably ask is: Will PHP 8 improve the performance of my website?

The answer to this question, as so often is the case, is "it depends..."

When PHP was upgraded from version 5 to version 7, there was a huge performance boost. With PHP 8, however, you won 't see an overall performance improvement unless your application computes a lot of mathematical functions (see our section on the JIT compiler). This is mainly because PHP's code optimization is already very well established.

But who says performance is limited to compile time anyway? As a developer, I would measure performance in several ways. One performance factor is having functions available for me to write well-structured code and that's where PHP 8 is full of treats. So, let's get started!

The most important new feature updates in PHP 8 

PHP 8 has eight new main features we'll look at today:  

  1. The JIT compiler 
  2. Attributes
  3. Named arguments
  4. Match expressions 
  5. Throw expressions
  6. Static return type 
  7. Union type 
  8. Mixed types 

The JIT (just-in-time) compiler(rfc)

When PHP code is run, it's usually done by compiling it into virtual instructions that are executed in a virtual machine. JIT will change this by compiling the code into x86 machine code and then running that code directly on the CPU. For applications that rely heavily on mathematical functions, this should improve performance. You shouldn't, however, expect improvements for average web applications (see graphic). 

PHP 8 - New Features, Improvements and Potential Problems with WordPress
Source

An example of what kind of performance increase can be achieved through JIT is demonstrated in this video: 

YouTube

By loading the video, you accept YouTube's privacy policy.
Learn More

Load video

PGlmcmFtZSBsb2FkaW5nPSJsYXp5IiBzcmM9Imh0dHBzOi8vd3d3LnlvdXR1YmUtbm9jb29raWUuY29tL2VtYmVkL2RXSDY1cG1uc3JJIiBhbGxvdz0iYWNjZWxlcm9tZXRlcjsgYXV0b3BsYXk7IGNsaXBib2FyZC13cml0ZTsgZW5jcnlwdGVkLW1lZGlhOyBneXJvc2NvcGU7IHBpY3R1cmUtaW4tcGljdHVyZSIgYWxsb3dmdWxsc2NyZWVuPSIiIHdpZHRoPSI1NjAiIGhlaWdodD0iMzE1IiBmcmFtZWJvcmRlcj0iMCI+PC9pZnJhbWU+

The bottom line is that your application will run more smoothly with the new version if you use PHP for labor-intensive math tasks. But if you use PHP like most WordPress users, however, you won't notice much of a change. More on what PHP 8 means for WordPress users later. 

Let's move on with the next features:

Attributes v2(rfc, rfc)

One new feature in PHP 8, and one which is hotly debated in the PHP community, is attributes - known in many other languages as "annotations". In PHP 8, attributes replace the docblocks metadata storage. This is what you needed to use previously to declare metadata for classes, methods, functions, and arguments in a structured way. 

As you can imagine, using code comments to apply metadata wasn't ideal but it did work. Fortunately, we won't have this problem anymore. 

Attributes can be declared with Syntax #[...] now instead.

Here are some examples from the RFC of how attributes can be applied to different data types.

#[ExampleAttribute]
class Foo
{
    #[ExampleAttribute]
    public const FOO = 'foo';
 
    #[ExampleAttribute]
    public $x;
 
    #[ExampleAttribute]
    public function foo(#[ExampleAttribute] $bar) { }
}
 
$object = new #[ExampleAttribute] class () { };
 
#[ExampleAttribute]
function f1() { }
 
$f2 = #[ExampleAttribute] function () { };
 
$f3 = #[ExampleAttribute] fn () => 1;

It's worth noting here that the RFC for attributes has undergone some changes since its original conception. This goes to show how much effort and thought has been put into this update. 

Named Arguments(rfc)

Named arguments give you more flexibility when calling functions. Until now, you had to call a function and pass each argument in the order specified by the function. 

// Using positional arguments:
array_fill(0, 100, 50);

With named arguments you can define a name for each parameter. And now you can call them out of order, as shown below: 

// Using named arguments:
array_fill(start_index: 0, num: 100, value: 50);

They can also be called like this:

array_fill(value: 50, num: 100, start_index: 0);

A hybrid of the two is also possible, allowing named parameters and positional arguments to be mixed and thus improving the readability of the code: 

htmlspecialchars($string, double_encode: false);

Match Expressions(rfc)

Match Expressions is intended to solve some long-standing problems in the functionality of its predecessor, Switch. 

Comparison Operator

Switch used a type-converting relational operator (==), which could cause problems. In contrast, match uses a strict comparison operator (===), independent of strict_types.

Return Value

Switch instructions often generate a value that is needed later in the program flow. If this value is missing from the Switch statement, it can lead to problems in the PHP script. In addition, the switch syntax makes it difficult to read nested statements.

switch (1) {
    case 0:
        $y = 'Foo';
        break;
    case 1:
        $y = 'Bar';
        break;
    case 2:
        $y = 'Baz';
        break;
}
 
echo $y;
//> Bar

The new match expression solves this problem by directly assigning the return value for each match branch (=>), which is more intuitive. 

echo match (1) {
    0 => 'Foo',
    1 => 'Bar',
    2 => 'Baz',
};
//> Bar

Fallthrough

If a switch statement doesn't have a break after each case, it will run to the next case, even if the intention was for the code to break. This was designed so that switch functions could execute several blocks of code in sequence. However, this has been a common source of bugs in the past. 

Match has implemented an implicit break after each arm (=>). Multiple conditions can now be executed by commas separating each condition:  

match ($x) {
    1, 2 => {
        // Same for 1 and 2
    },
    3, 4 => {
        if ($x === 3) {
            // Only 3
        }
        // Same for 3 and 4
    },
}

Throw expressions(rfc)

In PHP 8 the throw statement has become an expression. This means that technically, throw can now return a value. This is helpful in the sense that throw can now be used in many more places, e.g. in arrow functions or coalesce operators. 

Arrow Functions: 

$callable = fn() => throw new Exception();

Coalesce Operators: 

// $value is non-nullable.
$value = $nullableValue ?? throw new InvalidArgumentException();
 
// $value is truthy.
$value = $falsableValue ?: throw new InvalidArgumentException();

Ternary Operators:

// $value is only set if the array is not empty.
$value = !empty($array)
    ? reset($array)
    : throw new InvalidArgumentException();

Static Return Type(rfc)

As this RFC states, Static Return Type allows the return of the special class name "static" from a method: "The static special class name in PHP refers to the class a method was actually called on, even if the method is inherited. This is known as "late static binding" (LSB). This RFC proposes to make static also usable as a return type (next to the already usable self and parent types)."

Static cannot be used as part of a parameter in this case, however. The static return will refer to the class that was called. 

Union Types(rfc)

Union types allow you to declare the type of value you expect from an input. This is called a schema in some languages. It's syntactically defined by using  | (e.g. string|array|int) But the magic doesn't stop there. You can also use classes you've defined such as:

class MyClass {

}
function myFunction(string|array|int|MyClass){

}

Union types are already used in PHP. But they are implemented using the phpdoc annotations method, as shown below. 

class Number {
    /**
     * @var int|float $number
     */
    private $number;
 
    /**
     * @param int|float $number
     */
    public function setNumber($number) {
        $this->number = $number;
    }
 
    /**
     * @return int|float
     */
    public function getNumber() {
        return $this->number;
    }
}

Take a look at the below example from the RFC for a bit more context about usage.

class Number {
    private int|float $number;
 
    public function setNumber(int|float $number): void {
        $this->number = $number;
    }
 
    public function getNumber(): int|float {
        return $this->number;
    }
}

This basically means you can use multiple input types for the same function instead of just one, allowing for a higher degree of code reusability.

Mixed Types(rfc)

In recent versions of PHP, it was possible to declare the expected type of input and return data. However, PHP did not always support Types, and this is a problem. In some cases, a Type was omitted or simply forgotten. MixedTypes now tries to solve this problem.

A mixed type would be equivalent to array|bool|callable|int|float|null|object|resource|string

Here is an example from the RFC documentation of how this is used:

// Valid example
 
class A
{
    public function foo(int $value) {}
}
 
class B extends A
{
    // Parameter type was widened from int to mixed, this is allowed
    public function foo(mixed $value) {}
}

Additional PHP 8 features

Make Sorting Stable(rfc)

Stability is added to all functions that fall under Sort (for example.

sort, rsort, usort, asort, arsort, uasort, ksort, krsort, uksort, array_multisort)

I would recommend you read this in the RFC docs and compare it to your application, as changing this functionality from unstable to stable sorting could negatively impact your code.

Constructor Property Promotion(rfc)

This feature should help speed up your dev workflow and reduce errors. Currently, defining an object of values requires a set of boilerplates, as shown below in the RFC documentation:

class Point {
    public float $x;
    public float $y;
    public float $z;
 
    public function __construct(
        float $x = 0.0,
        float $y = 0.0,
        float $z = 0.0,
    ) {
        $this->x = $x;
        $this->y = $y;
        $this->z = $z;
    }
}

The properties must be repeated three times with this method. The improvement is the short formula below: 

class Point {
    public function __construct(
        public float $x = 0.0,
        public float $y = 0.0,
        public float $z = 0.0,
    ) {}
}

Zero Safe Operator(rfc)

There's a new operator on the block! 

Anstelle des klassischen <code>!== null</code> haben wir nun das bekommen: <code>?-></code>. Es scheint zunächst merkwürdig, aber wenn man es unter dem Gesichtspunkt der Verkettung von “if-Statements” betrachtet, dann wird die Anwendung ziemlich deutlich: 

$country =  null;
 
if ($session !== null) {
    $user = $session->user;
 
    if ($user !== null) {
        $address = $user->getAddress();
 
        if ($address !== null) {
            $country = $address->country;
        }
    }
}
 
// do something with $country
$country = $session?->user?->getAddress()?->country;
 
// do something with $country

str_contains(rfc)

This rather nice new function returns a boolean result (true/false) when a string is found in another string. It takes two arguments, the string to be searched in and the string being searched for.

str_contains('php8', '8'); // true
str_contains('php8', 'wordpress'); // false

For even more useful string filters, you should check out the following new features:

str_starts_with('haystack', 'hay'); // true
str_ends_with('haystack', 'stack'); // true

These two will both return a boolean result and work in the same way str_contains().

Weak Maps(rfc)

Usually when you set a variable to the value of an object in PHP, it will create a reference to that object but not a new object. 

In this case, you may end up with many references to an object but only one object. The issue here is when it's time to delete this object, PHP counts the number of references this object has and, if it's more than the object, PHP will refuse to delete that object. 

Weak Maps solves this problem by creating a "weak" reference to the corresponding object. Once the object is deleted, all variables with the Weak Maps reference to that object are set to zero. 

Non-capturing Catches(rfc)

A try-catch block is already pretty ingenious when it comes to error reporting and now there's an even faster way to implement it. And no, it won't really affect the readability. 

The "old school" way meant you had to pass your catch exception to a variable like this:

function catchMeWhenIFall(){
	try {
        throw new Exception('NOPE - GRAVITY');
    } catch (Exception $e) {
        return $e->getMessage();
    }

}

But now you don't need to define the variable to be passed to your catch block anymore.

try {
	throw new Exception('FOO!');
 catch  (){
	//Do some code here
 }

}

Further PHP 8 reading material

If you want to know more about the release of PHP 8 or check out the RFC code samples for yourself, just take a look at the official release announcement

Are you ready for PHP 8? 

No developer is a fan of updates that usher in big changes, let's not forget the debates around WordPress 5.0 and Gutenberg. Big changes mean there's a risk your code will break and leave you with hours of work or a complete rebuild on your hands. If your code worked cleanly with PHP 7.4, however, you shouldn't have any issues with PHP 8. More on PHP and WordPress in the next chapter. 

However, if you are running an older version of PHP, you should check the list of deprecated features before updating. See the PHP "Appendices" documentation for a complete list of previous features, changes and issues when updating from one PHP version to the next. 

Should you update your WordPress project to PHP 8? 

For well-typed codebases or codebases which have stayed up-to-date with the latest PHP versions, there isn't a big problem [to migrate to PHP 8]. The reality, however, is that WordPress is not such a codebase.

Omar Reiss, yoast

This quote from the Yoast "WordPress and PHP 8 Compatibility Report" already suggests that you as a WordPress user:in should not treat the update to PHP 8 lightly. The conclusion of the report reinforces this assumption, as Omar Reiss writes: "By just investigating a subset of breaking changes in PHP 8 we could already confirm this is likely to cause major breakage on sites with unclear origin of that breakage. Oftentimes the error will occur in one place, but is caused by a plugin or theme in a different place, making these issues hard to debug."

These compatibility issues are also a reason why PHP 8 is not immediately available in the RAIDBOXES dashboard for our customers. Especially after major updates, it always makes sense to give the Plugin developers enough time for possible adjustments and to wait for the time being. As soon as we can be sure that there are no problems with a standard WordPress installation and PHP 8 runs stable and performant on our system, we will of course make PHP 8 available.

If you already have access to PHP 8 and want to test the new version with your WordPress website, you should - as before every update - first create a backup. How to properly test a new PHP version at RAIDBOXES can be read in this Helpcenter article (here using PHP 7.2 as an example).

Conclusion

PHP 8 is a big step forward compared to previous versions. Depending on how you use PHP, you may not immediately see a dramatic improvement in performance. But you should consider updating after testing, once it's stable, and is available at your WordPress hosting provider. PHP 8 is a natural progression and by implementing the newer version sooner rather than later, you're creating a solid foundation for future expansion, growth and performance improvements.

Further questions about PHP 8?

I hope I was able to introduce you to the exciting new features of PHP 8 with this article. You have more questions about the topic? Feel free to use the comment function. You want more tips about WordPress , web design and more? Then follow us on Twitter, Facebook or via our newsletter.

As a web developer at RAIDBOXES, Marten is always working on new features for our customers. At "wp unboxed" he also scores with his knowledge of web development, WordPress and our dashboard. And in his spare time he likes to deal with self-hosting and the latest trends on the Internet.

Comments on this article

PHP 8 is definitely impressive in terms of performance, but the code is totally new and incompatible with earlier ones. I'll not recommend WordPress users to switch to the latest updates asap.

Please wait for the first few initial weeks, let the early adopters try it and fix everything. Many hosting companies are already pushing PHP8 in their library but stick to the PHP 7.4 and WP 5.5.3 for some time.

Post a comment

Your email address will not be published. Required fields are marked with *.