What is new in PHP 7.4?

What is new in PHP 7.4?

thumbnail

They say that the best is the enemy of the good, on the one hand, and that evergreen attitude brings big profits: like shortening the application’s response or performance improvement, on the other. 

In this article, you will read about changes added to the PHP 7.4 language. Let us assume we are looking for an e-commerce brand context, Magento 1.x engine, specifically speaking. 

What effects will migration from PHP 7.0 to PHP 7.4 bring? What are the consequences connected to it, both positive and negative?

Changes in PHP language [1] [4]

Arrow functions for cleaner one-liner functions [2] [7]

Short closures allow to simplify notation to less verbose one-liners.

It was allowed before to use the construction:

array_map(function (User $user) {

    return $user->id;

}, $users)

Now you can shorten it to:

array_map(fn (User $user) => $user->id, $users)

You do not need to write use keyword. Short closures have an access to the whole scope. $This operator is also available or other variables from the scope.f.e. $modifier

$modifier = 5;

array_map(fn($x) => $x * $modifier, $numbers);

or

array_map(fn($x) => $x * $this->modifier, $numbers);

The limitation is to use one line expression, that will be automatically filled with return keyword. You can not use it explicit. You can use types also:

$ids = array_map(fn(Post $post): int => $post->id, $posts);

Preloading to improve performance [3] [8]

Preloading is new low-level feature of PHP 7.4. This wonderful extension in the PHP core may result in a performance increase. Roughly speaking when you use a framework you need to load and link all its files in every HTTP request. Preloading allows loading all files to server’s memory during start and provide them permanently through all requests. Performance improvement generates also some costs. When the source of preloading files changes it will require restart of the server. Only this way changes will take effect.

How does it work?

  • in order to preload files, you need to provide dedicated PHP script,
  • this script is run when the server is starting its work,
  • all files preload in this way, are available in memory through all requests,
  • you will not see changes in the loaded source of files unless you restart the server.

Typed properties in classes [9]

Variables in classes, the so-called fields can have their own types, f.e.:

class Foo

{

    public int $a;

    public ?string $b = ‘foo’;

    private Foo $prop;

    protected static string $static = ‘default’;

}

class Foo

{

    public int $bar;

}

$foo = new Foo;

In the code above there is no error during the instantiating $foo object. It appears only when you try to reach its value without initialization:

var_dump($foo->bar);

you will see then fatal error:

PHP Fatal error:  Uncaught Error: Typed property Foo::$bar must not be accessed before initialization

Improved type variance and contravariance of arguments [10]

Type variance:

class ParentType {}

class ChildType extends ParentType {}

class A1

{

    public function covariantReturnTypes(): ParentType

    {

  //…

    }

}

class B1 extends A1

{

    public function covariantReturnTypes(): ChildType

    {

        //…

    }

}

Contravariance of arguments: 

class A2

{

    public function contraVariantArguments(ChildType $type)

    {

//…

    }

}

class B2 extends A2

{

    public function contraVariantArguments(ParentType $type)

    {

//…

    }

}

The null coalescing assignment operator as a shorthand [11]

Null coalesce operator was implemented in the previous version of PHP 7.

$data[‘date’] = $data[‘date’] ?? new DateTime();

Now you may use simplified notation:

$data[‘date’] ??= new DateTime();

FFI for better extension development in PHP [12]

FFIForeign Function Interface. This functionality allows calling code written in C, f.e.: 

// create FFI object, loading libc and exporting function printf()

$ffi = FFI::cdef(

    “int printf(const char *format, …);”, // this is regular C declaration

    “libc.so.6”);

// call C printf()

$ffi->printf(“Hello %s!\n”, “world”);

Underscores can be used to format numeric values [13]

PHP 7.4 allows using underscores as a visual separators numerical values. You can see it here:

$unformattedNumber = 107925284.88;

$formattedNumber = 107_925_284.88;

Underscores are just ignored by the PHP interpreter.

A spread operator in arrays [14]

From now on, you may use spread operators in arrays:

$arrayA = [1, 2, 3];

$arrayB = [4, 5];

$result = [0, …$arrayA, …$arrayB, 6 ,7];

// [0, 1, 2, 3, 4, 5, 6, 7]

Please notice that it works only with arrays with numerical keys.

Custom object serialization [15]

Two magic methods have been added:

  • __serialize 
  • __unserialize

The difference between them and between __sleep and __wakeup is described in RFC.

Reflection for references [16]

Libraries like Symfony’s dumper was strictly attached to API of reflection mechanism in order to dump variable reliably. It was not possible in PHP language in previous versions. You must have had additional extensions installed like f.e pecl-weakref or krakjoe/uref.

PHP in 7.4 version provides class ReflectionReference, which solves the issue.

Weak references [17]

Weak references are references for objects, but they do not protect them against destruction. They are useful in the implementation of data structures like cache type structures. In PHP 7 they are provided in a separate extension called pecl-poorref.

For instance:

get());  // object(stdClass)#1 (0) {}

unset($obj);

var_dump($weakref->get()); // NULL

mb_str_split added [18]

It provides the functionality in similar way to str_split but uses multi byte chains instead.

Here is an example:

print_r(mb_str_split(“победа”, 2));

–EXPECT–

Array

(

    [0] => по

    [1] => бе

    [2] => да

)

Password Hashing Registry [19]

According hashing libraries the way of using them has changed in order to make it simpler for users.

They added new function password_algos, to be precise. It returns a list of all registered password algorithms.

Ext/sodium can register dynamically hashing algorithms. As a result argon2i and argon2id  will be more commonly used in the future.

Left-associative ternary operator deprecation [20]

The ternary operator is used in a ridiculous (?) way in PHP sometimes. You can not use nested constructions without parenthesis now. They are deprecated in PHP 7.4. In PHP 8 there will be fatal errors thrown when you try to use it:

1 ? 2 : 3 ? 4 : 5;   // deprecated

(1 ? 2 : 3) ? 4 : 5; // ok

Exceptions allowed in __toString [21]

It was forbidden to throw exceptions In the __toString method before. It was done this way in order to avoid some core exception handling mechanisms. A user nicknamed Nikita who took part in the PHP voting process noticed that the previous solution was not actually a solution, that is why he proposed the change.

Concatenation precedence [22]

This construction:

echo “sum: ” . $a + $b;

was interpreted by PHP so far this way:

echo (“sum: ” . $a) + $b;

PHP 8 will interpret it this way:

echo “sum: ” . ($a + $b);

PHP 7.4 gives deprecation notice when encounters on expression without parentheses containing a .  a + or a –.

You will be shown the notice: 

PHP Deprecated:  The behavior of unparenthesized expressions containing both ‘.’ and ‘+’/’-‘ will change in PHP 8: ‘+’/’-‘ will take a higher precedence

array_merge without arguments [23]

From the time spread operator was created in PHP language there are possible situations where such an expression can be useful according to array_merge:

$merged = array_merge(…$arrayOfArrays);

In order to handle an edge case where $arrayOfArrays is empty, array_merge and array_merge_recursive both, will allow empty parameters’ list. An empty array will be returned if nothing is passed as an argument.

Curly brackets for array and string access [24]

You could have access to array or string using curly brackets:

$array{1};

$string{3};

In PHP 7.4 it is deprecated.

Invalid array access notices [25]

If you tried to access an integer variable like an array you would retrieve a null value. Now you will receive a notice:

PHP Notice:  Trying to access array offset on the value of type int

$i = 1;

$i[0]; // Notice

proc_open improvements [26]

There are changes made in function proc_open. That will prevent the flow from going through shell. An array is sent as a parameter instead of a string command.

strip_tags also accepts arrays [27]

Previously in order to skip several tags, you must have to list them all in a string:

strip_tags($string, ‘<a><p>’)

PHP 7.4 allows us to use an array:

strip_tags($string, [‘a’, ‘p’])

ext-hash always enabled [28]

This extension is permanently enabled and accessible in PHP 7.4.

PEAR not enabled by default [29]

PEAR is not maintained anymore that is why the core team decided to remove default installation in PHP 7.4.

Several small deprecations [30]

On RFC site there are mentioned some features, that are deprecated. There are also voting rankings of core team attached to each functionality note:

  • The ‘real’ type,
  • Magic quotes legacy,
  • array_key_exists() with objects,
  • FILTER_SANITIZE_MAGIC_QUOTES filter,
  • Reflection export() methods,
  • mb_strrpos() with encoding as 3rd argument,
  • implode() parameter order mix,
  • Unbinding $this from non-static closures,
  • hebrevc() function,
  • convert_cyr_string() function,
  • money_format() function,
  • ezmlm_hash() function,
  • restore_include_path() function,
  • allow_url_include ini directive.

Other changes [4] [31]

Here are some changes mentioned:

  • Using keyword parent:: in a class without a parent is now deprecated,
  • Using var_dump according to DateTime and DateTimeImmutable objects will not allow seeing properties available,
  • openssl_random_pseudo_bytes will throw an exception in case of errors.
  • when you try to serialize an instance of PDO or PDOStatement you will receive Exception  type instead of PDOException,
  • Calling function get_object_vars() on a type of ArrayObject will return properties of the object not the properties of hidden object nor array in it. It is worth noticing that cast arrays have not been changed,
  • ext/wwdx was deprecated.

Performance [4] [5]

When you would like to compare performance differences you can see benchmarks results among different PHP versions that blog jchost.pl publishes. You can see a comparison between PHP 7.4 and different PHP versions like 5.6.x, 7.0.x, 7.1 and 7.2.x:

  • 187% higher than PHP 5.6.40
  • 38% higher than PHP 7.0.33
  • 7% higher than PHP 7.2.22

Speed

You can see the table below that presents a comparison of the response time of PHP scripts. There are two kinds of scripts that were measured: one displaying classic message Hello World and the second that represents a single API endpoint (see [5]).

Magento migration consequences from PHP 7.0 to PHP 7.4

A lot of Magento versions 1.x are run on stable and solid versions of PHP. For some projects, it will be still PHP in 5.6 versions for smaller shops. More often you can encounter a newer version with PHP 7.0 or PHP 7.2. PHP 7.4 migration can be challenging. It is worth to consider all the risks before doing it much earlier. A lot of changes that must be done on so low levels, like the language level, will bring necessity to put much effort in programs work to find bugs and fixed them. Some of them may be difficult to diagnose. It may turn out necessary to deploy changes in many modules and its dependencies. Financial modules belong to these the most expensive. In an e-commerce brand, there 

are payment modules and modules responsible for calculating statistics, calculation prices or importing/exporting products. All the bugs and inconsistencies in these modules will cause financial losses. It is a critical point for online shops.

The increase of performance that comes with PHP 7.4 is appealing on the one hand. It is some kind of investment on the other. The condition to achieve this is to create a loading script and configure it in OpCache settings in a proper way. There are limitations and costs behind it. Any change in the source of preloaded files will require a restart of the server.

Evergreen attitude is an attitude towards development and growth. It is right to keep on learning new technologies and developing new skills and discover more and more strategies to resolve problems. It is very good for the team of programmers both experienced and for newly hired employees without experience. Though it is not always good for clients’ demands and profits in a short time perspective. From their point of view rewriting modules, that were working properly so far, means rather longer than a short period of time, when they will not be working properly. It means also a delay in the commissioning deadline. When you try to change foundations of the code you will receive for sure a lot of bugs and encounter new problems. That may cost you a decrease of your incomes and an increase in the unhappiness of the end customers. Of course in the long perspective of migration to a higher version of PHP the goal is to improve the overall performance and those parameters mentioned before and to achieve a shorter time of HTTP response.

You should consider the risk and profits with your team. You should be mentally prepared for a huge effort to achieve the success point. But also you should expect the increase of attractivity of your product, more efficient work of your service which will give you a raise in revenue. Personally I reckon that it is worth investing in PHP application development and the new technologies. Let me quote here what Brian Tracy used to say: “The key to success is to focus our conscious mind on things we desire not things we fear.” [32].

Author: Jarosław Zieliński

References:

[1] https://stitcher.io/blog/new-in-php-74
[2] https://stitcher.io/blog/short-closures-in-php
[3] https://andrewdavis.me/post/introduction-to-php-7-4-preload/
[4] https://jchost.pl/blog/php-7-4/
[5] http://www.phpbenchmarks.com/en/comparator?phpVersions= php-5.6%7Ephp-7.0%7Ephp-7.1%7Ephp-7.2%7Ephp-7.3&groups=php-5.x%7Ephp-7.x&components=
[6] The PHP 7.4 series (Deprecations)
[7] rfc:arrow_functions_v2
[8] PHP: rfc:preload
[9] rfc:typed_properties_v2
[10] PHP: rfc:covariant-returns-and-contravariant-parameters
[11] rfc:null_coalesce_equal_operator
[12] rfc:ffi
[13] rfc:numeric_literal_separator
[14] rfc:spread_operator_for_array
[15] rfc:custom_object_serialization
[16] rfc:reference_reflection
[17] rfc:weakrefs
[18] PHP: rfc:mb_str_split
[19] rfc:password_registry
[20] rfc:ternary_associativity
[21] rfc:tostring_exceptions
[22] rfc:concatenation_precedence
[23] https://github.com/php/php-src/blob/PHP-7.4/UPGRADING#LC358
[24] rfc:deprecate_curly_braces_array_access
[25] PHP: rfc:notice-for-non-valid-array-container
[26] https://github.com/php/php-src/blob/PHP-7.4/UPGRADING#LC362
[27] https://github.com/php/php-src/blob/PHP-7.4/UPGRADING#L335
[28] rfc:permanent_hash_ext
[29] Disable PEAR by default
[30] rfc:deprecations_php_7_4
[31] https://github.com/php/php-src/blob/PHP-7.4/UPGRADING
[32] Brian Tracy – The key to success is to focus our conscious…

...