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 feature freeze since July. This meant that until its release on November 26th, no further features were allowed to be added. A special feature of this version is that PHP 7.5 has been skipped and we've moved directly to PHP 8. And this jump brings a lot of new features. 

One of the most common questions WordPress users will ask about PHP 8 is probably: 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 updated from version 5 to version 7, it brought with it a huge performance boost. But with PHP 8 you won't see any general improvement in performance, unless your application calculates many mathematical functions (see our section on the JIT compiler). This is mainly because the code optimization of PHP is already 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 downloading the video you accept the YouTube privacy policy.
Learn more

Load video

PGlmcmFtZSBzcmM9Imh0dHBzOi8vd3d3LnlvdXR1YmUtbm9jb29raWUuY29tL2VtYmVkL2RXSDY1cG1uc3JJIiBhbGxvdz0iYWNjZWxlcm9tZXRlcjsgYXV0b3BsYXk7IGNsaXBib2FyZC13cml0ZTsgZW5jcnlwdGVkLW1lZGlhOyBneXJvc2NvcGU7IHBpY3R1cmUtaW4tcGljdHVyZSIgYWxsb3dmdWxsc2NyZWVuPSIiIHdpZHRoPSI1NjAiIGhlaWdodD0iMzE1IiBmcmFtZWJvcmRlcj0iMCI+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. Previously, you had to call a function and pass each argument in the order in which the function specified. 

// 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 are intended to solve some long-standing problems in the functionality of the 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 says, static return type allows you to return 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)."  

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

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 more recent PHP versions, it's been possible to declare the expected type of input and return data. PHP hasn't always support types, however, and this has caused problems. In some cases, a type was omitted or simply forgotten. Mixed Types is now trying 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 recommend reading about this in the RFC documentation and comparing it with your application first. Changing this functionality from unstable to stable sorting could negatively affect your code.

Constructor property promotion (rfc)

This feature should help to speed up your development workflow and reduce errors. Currently, defining an object of values requires a lot of boilerplate code, as you can clearly see in the example from the RFC documentation below:

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,
    ) {}
}

Nullsafe operator (rfc)

There's a new operator on the block! 

Instead of the classic !== null, we've now got: ?->. It seems strange at first but if you look at it from the point of view of chaining "if statements", its application becomes pretty clear: 

$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 object in question. Once the object is deleted, all variables with the weak maps reference to this object are set to null. 

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'd like to know more about the release of PHP 8, or you want to see the RFC code samples for yourself, just have 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. 

If you're running an older version of PHP, you should check the list of deprecated functions before updating. In the PHP "Appendices" documentation you'll find a complete list of previous features, changes, and problems 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

The quote above from the yoast "WordPress and PHP 8 Compatibility Report" already suggests WordPress users shouldn't take the decision to upgrade to PHP 8 too rashly. The report's conclusion reinforces this 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. Often 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 for our customers in the RAIDBOXES Dashboard. Especially after major updates, it's always a good idea to give plugin developers enough time to make any necessary adjustments and simply wait it out for a while. We will, of course, make PHP 8 available as soon as we can be sure there are no problems with standard WordPress installations and that PHP 8 runs stable and performant on our system. 

If you already have access to PHP 8 and want to test the new version with your WordPress website, you should, as with every change, create a backup first. Find out how to test new PHP versions properly at RAIDBOXES in in our Help Center article (using the example of PHP 7.2).

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 this article has helped you understand the exciting new features of PHP 8. Do you have any further questions on this topic? Please use the comment function. Do you want more tips on WordPress, webdesign and more? Follow us on Twitteror Facebook , or subscribe to 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

An
Atul Host

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 pushed PHP8 in their library but stick to the PHP 7.4 and WP 5.5.3 for some time.

rednom

using javascript as a reference is a good idea to illustrate what's lacking in php thanks for the idea ! I've used it in my article about php 8 new updates as well 😉

Leave a comment

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