Skip to content

Blog

PHP 8: New Features and Performance in the Improved Version

Nicola Bettini

After a relatively quick testing phase, it really looks like we are there: on 26 November 2020, the new major version PHP 8, the best-known programming language for server development, will be available to everyone.

In the article that follows, let’s discover together the main new features and the performance of the new version of this language.

The move from PHP 7 to PHP 8

Created by the developer Rasmus Lerdorf twenty-five years ago to build dynamic web pages, PHP is the best-known programming language for server development, and over time it has grown into a complete, professional language, thanks also to the support of the community and of the professionals around it.

The term major version matters: just as PHP 7 introduced changes that broke compatibility with PHP 5.6, here too we should expect a significant technological leap that will bring many breaking changes.

Exactly as in the move from PHP 5.6 to PHP 7, the real difference will be made by the quality of the code and by each developer’s ability to keep up to date; using frameworks such as Symfony, Laravel and Yii can help in handling version changes this significant, because they force the developer to write code that is as abstract and high-level as possible.

The main new feature of PHP 8: JIT

The main new feature of this version is support for JIT compilation (Just-in-Time), whose job is to improve performance by interpreting and compiling parts of the code line by line at runtime, that is, during execution. In practical terms, then, JIT is a way of compiling while an application is actually running, which is why we talk about “dynamic translation”: it happens during execution rather than before it.

The execution phases of PHP 8 with OPcache

The PHP 8 execution procedure is made up of four phases:

  • Lexing/Tokenizing to build a set of tokens.
  • Parsing using the tokens, to build the AST, that is, the hierarchical representation of the source code.
  • Compilation: the interpreter translates the AST nodes into low-level Zend opcodes, which determine the type of instruction executed by the Zend VM.
  • Interpretation: the opcodes are interpreted and executed on the Zend VM.

Enabling OPcache makes it possible to speed up operations and optimise machine performance, with content available immediately and no waiting. In other words, with OPcache the PHP interpreter goes through the four phases of the procedure only the first time the script is run, making the bytecode of the low-level intermediate representation immediately available to be executed on the Zend VM.

The main characteristics of PHP 8

PHP 8 has in fact caught up with the robustness of the most renowned legacy systems, while keeping the exclusive characteristics that make it a safe method:

  • Structured: the new release is characterised by typing, which brings greater control and stability to the platform.
  • High-performing: safe in terms of performance and control during development, build and deploy.
  • Standardised: greater consistency in the responses returned by system functions.

At dotenv the development team already works with PHP 7.4, released last November, in order to guarantee ever better performance. With the release of the new version we will therefore update our methods and procedures further, confident of the advantages PHP8 will bring, after the release of the Beta1 version on 6 August.

The new features of PHP 8

Union Types

Link to the RFC

This was, personally, one of the gaps I felt most when declaring functions; the risk, as always, will be that the feature gets abused; let’s look at an example:

public function foo(Foo|Bar $input): int|float;

Before PHP 8, the only option for returning one or more values was null alone, for example with

public function foo(?Foo $input): ?int;

in this example I can return null or int, and the function accepts an $input of type null or Foo. But what happens if the return value is, say, an int and a float? I could not have done it. This does not apply when void is used: if a function returns nothing, I cannot expect any data type other than void (it would make no sense to say that the return value is int or void).

public function foo(Foo|null $foo): void;

public function bar(?Bar $bar): void;

JIT

Link to the RFC

On paper the Just in Time compiler promises significant performance improvements, although everything will depend on the specific use case. For the web, there are benchmarks that seem to debunk this myth. We will see in the coming months, especially because the stable version could be far more optimised.

The nullsafe operator

Link to the RFC

Hands up anyone who has ever run into the error Fatal error: Call to a member function getFoo() on null; this happens because the code is perhaps written like this

$object->bar->getFoo();

but bar is null. The only solution was therefore to use a ternary operator (or to check in two steps whether bar exists), for example:

$startDate= $booking->getStartDate();

$dateAsString = $startDate ? $startDate->asDateTimeString() : null;

So if $startDate exists in this case I call the asDateTimeString() function, otherwise I return null.

In PHP 8 everything becomes much more readable and clean

$da

$dateAsString = $booking->getStartDate()?->asDateTimeString();

That ? is doing exactly the same thing, but in a faster and more readable way.

Named arguments

This is a big new feature that will certainly help make code more readable. Until today the arguments passed to a function were positional: so if the first element was $a and then $b, the values to pass had to follow that order.

Let’s take this structure:

class CustomerData

{

public function __construct(

public string $name,

public string $email,

public int $age,

) {}

}

At the moment, once it is invoked, the order to follow is defined by the function signature; notice how convenient this is:

$data = new CustomerData(

age: $input['age'],

name: $input['name'],

email: $input['email'],

);

this way I do not have to remember the position of the elements but their name, which makes everything much more readable and linear. In the example of the structure you will see the next new feature of PHP 8, Constructor property promotion.

Constructor property promotion

Link to the RFC

A very convenient thing that will spare you useless, repetitive lines of code. We go from:

class Money

{

public Currency $currency;

public int $amount;

public function __construct(

Currency $currency,

int $amount,

) {

$this->currency = $currency;

$this->amount = $amount;

}

}

to

class Money

{

public function __construct(

public Currency $currency,

public int $amount,

) {}

}

As you can see, I have spared myself the definition of the variables at the top of the Money class as well as the assignment in the constructor.

Match

Given that I am not particularly fond of switch-case statements, since I find them, just like else, not very readable or functional, match lets us have, in compact form, what we would do with a switch.

You have surely seen something like:

switch ($statusCode) {

case 200:

case 300:

$message = null;

break;

case 400:

$message = 'not found';

break;

case 500:

$message = 'server error';

break;

default:

$message = 'unknown status code';

break;

}

well, all of this can be shortened into something much simpler and more readable:

$message = match ($statusCode) {

200, 300 => null,

400 => 'not found',

500 => 'server error',

default => 'unknown status code',

};

the break statements disappear and several values can be grouped together if the result is the same. It also returns a value that is already assigned to a variable, with no need to repeat $message = every time.

Strings

Link to the RFC Link to the RFC

Some new functions are available in PHP 8, for example str_contains() will return true or false without having to go through strpos any more

if (strpos('string with lots of words', 'words') !== false) { }

becomes

if (str_contains('string with lots of words', 'words')) { }

in the same way we also have two other functions:

str_starts_with('haystack', 'hay');

str_ends_with('haystack', 'stack');

Trailing comma in parameter lists

Link to the RFC

How many times, used as you are to arrays for example, have you found yourself adding a comma after the last parameter of a function? Now it is finally possible:

public function(

string $parameterA,

int $parameterB,

Foo $objectfoo,

) {

}

::class for objects

Link to the RFC

One last new feature, small but decidedly handy: instead of using get_class() on objects, it will be possible to use the better-known ::class

$foo = new Foo();

var_dump($foo::class);

notice how I can, at last, use ::class on $foo.

PHP 8 certainly brings a breath of novelty and fresh air, forcing developers to use syntax that is more and more like other languages and to leave behind more and more of the legacy notions that have, over the years, damaged its reputation.

The leap will therefore not be as significant as the one from PHP 5 to PHP 7, precisely because a great deal of modernisation work has already been done.

Now it is up to developers to write good code and use these new tools; everything that has been removed in PHP 8 (and has therefore become a breaking change) can be found in the upgrade guide.

Source: stitcher.io and Brent

At dotenv there is no shortage of skills when it comes to programming languages. The developers are a varied group who follow precise procedures to reach precise goals and release high-performing software to clients.

Discover dotenv’s Design, Development and Delivery processes.

If these topics interest you, we also talk about them out loud.

Nessun Segnale is dotenv’s podcast: 41 episodes, with guests who build software and products.