Introduction to PHP 7.4



As always winter as arrived,



From a couple of years in a row now (I wouldn’t imagine to ever say that) it is bringing a new version of PHP with it.

While we are all waiting for the major release of PHP 8, scheduled for September 2021, and its long-waited features, the inclusion of JIT above all, on November the 28th 2019 the new version, PHP 7.4 will be officially released.

The goal of PHP 7.4 is to improve the speed and the performance of your code, another objective is to increase its readability.

It has a lot of new features and functions but it also came with several deprecations and few incompatibilities that you need to take care of in you want to migrate.

We got a lot to cover so let’s jump straight to it.

This article is part of the series called “PHP 7.4” and includes:

What is new in PHP 7.4 and why you should care

table of content:

Typed Properties now supported

Spread operator

Arrow Functions

Null Coalescing Assignment Operator

Covariant Returns and Contravariant Parameters

Weak References

Preloading

New Custom Object Serialization Mechanism

Foreign function interface or FFI

Numeric Literal Separator

Reflection for references

mb_str_split

Password Hashing Registry



One of the most commented features of this RFC was to be able to type the properties of a class (the result was an astonishing 70 positive to 1 negative vote).

Type hinting on methods has been around for a while now, and we all know why it is good practice to use it, now we are going to the next level.

Type properties consist of allowing us to define several types of variables for our parameters.



The typed properties now supported are:

bool

int

float

string

array

object

Iterable

Self

Parent

we can also type classes’ name

and interfaces name

plus the nullable type (by typing a questing mark before the type)

If you do not know all or some of the words just mentioned I would advise having a look at this post about the basics of PHP.

It is not possible though, to type variable of type void

The reason being it won’t be and it has a syntax that can be easily misunderstood and the type callable reason being its behavior changes depending on the context.

We can also type static properties by inserting the type between the keyword static and the name of the variable.

All the examples in the snipped below are valid and can be used.

class User { // declaring scalar private int $id; public string $name; // declaring iterable public iterable $iterables; // desclaring classes and interfaces protected ClassName $classType; // desclaring variable with default value public string $name = "Nico"; // desclaring variable with nullable value public ?string $void = null; // desclaring more variable of same time at once public float $x, $y; // desclaring using keyword var var bool $flag }

In case you declare a property and then set it using another type you are going to get a Fatal error: Uncaught TypeError.



With 43 positive votes to 1, another popular feature in this release is the spread operator, also called argument unpacking,

To tell the truth, this feature has been available since PHP 5.6 but was only reserved when dealing with a list of arguments of a function.



in PHP 7.4 It will be available when defining an array as well.

The spread operator has, more or less, the same purpose of the array_merge() function but, since this is a PHP core construct rather than a function the improvement in speed and memory performance is quite impressive.

Let’s start with the syntax, you can use the spread operator by prepending three dots before an array or a Traversable instance, generator function included!

$mammals = ['bear', 'ape']; $animals = ['owl', 'crocodile', ...$mammals, 'frog']; array(5) { [0]=> string(3) "owl" [1]=> string(9) "crocodile" [2]=> string(4) "bear" [3]=> string(9) "ape" [4]=> string(4) "frog" }

Easy right?

We can also use this operator to expand arrays from other arrays formed the same way:

$mammals = ['bear', 'ape']; $animals = ['owl', 'crocodile', ...$mammals, 'frog']; $domain = [...$animals, …$fungus, …$plant];

I believe that the spread operator will make the best of itself when it is used alongside functions or generators like so.

function getMammals(){ return ['bear', 'ape']; } $animals = [...getMammals(), 'owl', 'crocodile']; function generateFungus() { $fungus = ['porcino', 'portobello']; yield $fungus; } $domain = ['bear', 'ape', 'pine', 'lettuce', ...generateFungus()];

The core developers of PHP did an amazing job and are now allowing us to write less code and enhance the readability of our scripts.

To be completely honest with you I believe that anonymous functions are not the best feature supplied by PHP.

But I admire the effort that the core team has put to improve it.

With 51 votes up against 8, there will be a few syntax changes to this particular trait of the language.

Let’s start by having a look at how it worked before PHP 7.4:

$mammals = ['bear', 'ape']; $animals = function($animals) use($mammals){ return array_merge($animals, $mammals); };

An arrow function can inherit variables passed by using the use keyword, as shown above, this is a quite tricky way to pass parameters and for someone who sees this keyword for the first time it may look quite confusing.

Another example is when using array functions like array_map() or array_filter(),

if you do not know what those functions do, head over the series PHP array function exposed.



In that case, you would do something like this:

function counterize($domains) { return count($domains); } $domains = ['bear', 'ape', 'pine', 'lettuce','porcino', 'portobello']; $plurals = array_map('counterize, $domains);



Invoking a counterize function using the first parameter of array_map() and passing the items to it.

With arrow functions, you can refactor this code in one line, (actually you must do it on one line since you cannot use it for multiple ones).

You also have to use the fn keyword at the beginning.

$domain = ['bear', 'ape', 'pine', 'lettuce','porcino', 'portobello']; $plurals = array_map(fn($domains) => count($domains), $domains);

There is a lot of room for refinement on this feature but the good news is that it has already improved a lot.

For example, now you do not need to utilize the use keyword anymore if you want to pass a variable also anonymous functions can be used in methods within a class and you can utilize $this variable in it as you do for other methods.



Here is a little cherry on top of a cake for us.



PHP 7 had released two operators that I personally love to use one is the spaceship operator the other is the null coalescing operator.

Two little nuggets that are making my code way more readable.

Now we are taking a step further on the null coalescing operator

A bit of background, what is the null coalescing operator?



Let’ pretend you have to assign a value of a variable according to a query string.

$animal = (isset($_GET['animal'])) ? $_GET['animal'] : 'none';

A simple ternary operator,

If an animal’s string is inside the superglobal variables $_GET the code above assigns the value to the $animal variable otherwise the variable became 'none'.



Let’s improve it according to PHP7 onwards.

$animal = $_GET['animal'] ?? 'none';

Much better isn't it?



Let’s now imagine that the variable passed was more “talkative”.

$this->request->data['theAnimalSpecieThatIsTheKingOfTheSavanna'] = $this->request->data['theAnimalSpecieThatIsTheKingOfTheSavanna'] ?? 'none';

Now the snippet does not look so great anymore

Hence the arrival of a new operator:

The Null Coalescing Assignment Operator

We can now rewrite the same code by writing

$this->request->data['theAnimalSpecieThatIsTheKingOfTheSavanna'] ??= 'none';

If the variable before the operator is set we get it otherwise we set the variable as ‘none’.

In computer science, variances are properties that characterize some operators on types.

There are three types of variances;

Invariant if the parent type constrains the type of the subtype, covariant if it preserves the subtype relation and contravariant if it reverses it.

You will see that (but for a couple of exceptions) PHP has invariant parameter and return types.

When learning about this concept it was almost impossible to find good examples online so I’ll try to make it as easy as possible here.

Class Animal {} Class Mammals extends Animal {} Class Factory { public function make() :Animal {} } Class ChildFactory { public function make() :Mammals {} }

The code above is sound because the ChildFactory create and instance of Mammals that is an Animal, note that we are also not violating the Liskov's SOLID principle

Class Animal {} Class Mammals extends Animal {} Class Factory { public function use(Mammals): {} } Class ChildFactory { public function make(Animal) {} }

Here we have something similar but the other way around, the main Factory accepts something specific instead the child method accepts a more wide parameter.

This is called the contravariant parameter type and it is now allowed in PHP 7.4.

I must admit I have never seen a real-world example of this and I forecast it will rarely use anyway.





Weak reference has been around for several years it is actually a common practice in programming languages such as C#, Java, and Python.

However, this is a new concept in PHP and if you are new to it wrap your head around it will be challenging.

What are Weak References?

The PHP manual tells us that Weak references are allowing to retain a reference to an object without preventing the object from being destroyed.



What?



Let’s see the syntax and then we’ll see why would you use that:

$animal = new Animal; $weakreference = WeakReference::create($animal); var_dump($weakreference->get()); unset($obj); var_dump($weakreference->get()); object(Animal)#1 (0) { } NULL

The first time we dump the variable we see the object the second time we still keep the reference even though the value returned is equal to null.

The syntax is very easy, now the task is to understand why would we use that? And when?

The answer is: sporadically.



I am quite sure that 98% of your application will almost never need this new feature, at least for the time being.



You will need it in certain cases though,



If you have some data that you have fetched in a cache, chance are you do not want to re-fetch the data over and over,

in case you need more memory you can unset some of the values you don’t need at the moment, substitute it with some relevant data that you may need straight away then get the old data back again.



You can do this by keeping the reference (or in this case weak reference) of the data you want to restore.

The pros are that you are saving a lot in terms of memory usage, thus performance.



The cons, in my opinion, is that, for the time being, this feature does not seem to be fully developed (at least in PHP 7.4) and we will need a few more versions of PHP to be fine-tuned.



There is a lot to talk about in this new feature.

Here we are talking about the PHP lifecycle.

Preloading consists of the procedure of loading libraries or frameworks into a thing called OPCache, the goal here is to improve the performance of the PHP engine and we do so by storing the script into the disk.

To make a sports example is like when a player warms up his muscles before getting into the field, he will be ready and responsive from the first action, whereas if he stayed on the bench for a long time he will feel stiff and unable to move quickly.

I know, you noticed the word OPCache and wandering what is it about, here is a quick explanation

Opcache takes care of your PHP source files, it compiles it to "opcodes", and store those elaborated files on the disk.

Opcodes is a low-level representation of your code,

therefore opcache avoids the action of translating your source files to the code that needs to run at runtime.

From here the improved performance.

The preloading will be controlled by a directive in the php.ini called opcache.preload.

It specifies the PHP script that must be compiled when the server starts.

Here is the catch,

If the opcache uses a directive to preload the files and make them available faster when your server starts,

then, if you edit these files there will be no effect because the file has already been saved.

Make sense?

To solve this issue and make the modification effective you must restart the server.

This is an annoying downside if your application is already in a production environment.





This is another feature proposed by Nikita Popov and it passed with 20 to 7 votes at the moment if you want to serialize an object you have three choices:

The __sleep() magic method

The __wakeup() magic methods

And the Serializable interface

Click this to learn about the magic methods in OOP and instead here you can dive into the object-oriented interface.

Nikita Popov says that all the options here have issues and the code they need in order to get the outcome is not reliable and can lead to various problems.

To solve these obstacles we will now have two brand-new specific magic methods, the serialize() that will return an array and the unserialize that requires an array to start with.

If you are developing an API consider this as a treat!

// Returns array containing all the necessary state of the object. public function __serialize(): array; // Restores the object state from the given data array. public function __unserialize(array $data): void;

You may consider this either as the best thing that ever happens to PHP or a thing that you are never going to use and will make an effort to forget the moment after you close this post.

FFI is an extension that promises to allows to load libraries that call C functions or access C data structures in PHP.

The good thing is that you do not need to learn an intermediate language to use FFI, there will be several static methods that will perform actions on the C data.

As the manual states, FFI is not only in an experimental phase by it is even considered dangerous, this class works with a very low-level language and you need to be able to use C to work with it.

Here is an example of the code you will be writing:



// create an FFI object using the static method, load the standard C library (libc) and eventually export the text with the function printf() $ffi = FFI::cdef( "int printf(const char *format, ...);", "libc.so.6"); // call C's printf() $ffi->printf("Hello %s!

", "world"); // Hello world!



If you love C and you are willing to improve your PHP scripts by using a lower-level language, now you can do it.



Anyway, note that to lower the risk, this FFI API may be restricted with the ffi.enable directive in the php.ini.





This is just a little feature to improve the readability of your code.

In PHP 7.4 you are now allowed to use underscores to separate numbers.

6.674_083e-11; // float

299_792_458; // decimal

0xCAFE_F00D; // hexadecimal

0b0101_1111; // binary

Be aware, using this now PHP tools for storing data like phone, credit card, and social security numbers is almost always a bad idea because these numbers often have prefixes and leading digits that are important.



As a rule, if the number is not going to be used in mathematical operators probably isn't the best way to store it.



Until PHP 7.3 libraries and frameworks that performed operations of dumping and comparing are forced to use a roundabout to detect references.

A famous example is VarCloner, a component of Symfony's debug that uses complicate approaches to detect the reference of unique cookies.

Nikita Popov proposed to the class ReflectionReference to solve this, it provides the functionality of spl_object_hash(), but for references instead of objects,

This is the actual class.

final class ReflectionReference { /* Returns ReflectionReference if array element is a reference, null otherwise. */ public static function fromArrayElement(array $array, int|string $key): ?ReflectionReference; /* Returns unique identifier for the reference. The return value format is unspecified. */ public function getId(): int|string; private function __construct(); // Always throws private function __clone(); // Always throws }

This is a much cleaner way to get the references especially now that in PHP 7.4 we are having typed variables.



Another little improvement here.

The function str_split() first arrived in PHP 5 and its scope is to convert a string to an array.

Here is the full spec:

str_split ( string $string [, int $split_length = 1 ] ) : array

As you can see it accepts a string as the first parameter and an integer as an optional second that indicates the maximum length of the chunk.

Here is an example:

print_r(str_split("mammals")); Array ( [0] => m [1] => a [2] => m [3] => m [4] => a [5] => l [6] => s )

mb_str_split() does the same things but like all the other mb_* function it operates on code points rather than bytes.



This feature was proposed by Sara Golemon.

Her proposal look for a solution of a problem on Linux distros where php-src is kept lean, with additional extensions being provided in separate packages,

She proposed a password hashing registry mechanism similar to the Hash extension's php_hash_register_algo() API.

The result is the new PHP function password_algos(),

It will return an array with the complete list of all registered password hashing algorithms.

The value of this array will be the human hash identity which anyway could not correspond to the human-readable name for the algo.

Here is an example of the function:

print_r(password_algos()); Array ( [0] => "2y" // Ident for "bcrypt" [1] => "argon2i" [2] => "argon2id" )

Conclusion of the first part



Like last year, it looks like that even this winter we will get a good amount of presents from the developers that work at the core PHP team.

This is not a breaking-charger version but it is used as a foundation for what PHP 8 is going to be in 2021.

There are a lot of new interesting features that need to be learned to exploit the language in its entirety and some of them like type variables, the Covariant Returns, and Contravariant Parameters are here to stay and improve over time.

If you want to master PHP, you have to learn them, if you believe you are already mastering this language, think again.

What you can do next?

Now that you discovered all the new features it is time to get your applications ready to implement them.

You can do that by removing all the deprecated items in the RFC of PHP 7.4.

Also, In order to get ready to fully understand PHP 7.4, (which has the official release date on the 28th of November) you need to know what’s in PHP 7.3.

The link above is a good place to start.

