BreadcrumbHomeResourcesBlog What’s New In PHP 7.4 January 30, 2020 What’s New in PHP 7.4PHP DevelopmentPerformanceBy Maurice KherlakianPHP 7.4 was released on November 28, 2019. As the last release before PHP 8, which is expected at the end of 2020, PHP 7.4 introduced a slew of new and updated features. Table of ContentsPHP 7.4 Performance: Better Than Previous ReleasesLearn More About PHP 7.4Table of Contents1 - PHP 7.4 Performance: Better Than Previous Releases2 - Learn More About PHP 7.4Back to topPHP 7.4 Performance: Better Than Previous ReleasesWith every new PHP release we can usually expect a small performance increase, and this one seems to be no exception. This newest version also provides capabilities that help developers write more concise code. In this blog, we’ll review the key features in PHP 7.4, including:Syntactic improvementsEngine changesClass preloadingForeign function interface (FFI)Deprecations and other language changesSyntactic ImprovementsPHP 7.4 supports syntax improvements including the addition of:Arrow functionsSpread operator in arraysCoalescing assign operatorNumeric literal separatorArrow FunctionsIn PHP 7.4, you can write short closures, also known as arrow functions. They provide a shorthand syntax for definingfunctions. Additionally:They can only have one expression.“return” keyword is not allowed.They can access variables in the parent scope without the “use” keyword.Arguments and return types can be type-hinted.For example, here is a snippet of code I wrote with PHP 7.3: <?php $arr = [1,2,3,4]; $new_arr = array_map(function($e) { return $e * $e; }, $arr); print_r($new_arr); //[1,4,9,16] In PHP 7.4, I can write the snippet like this:<?php $arr = [1,2,3,4]; $new_arr = array_map(fn($e) => $e * $e, $arr); print_r($new_arr); //[1,4,9,16] Here’s another example of code written with PHP 7.3, without an arrow function, and with a “use” statement to get $coefficient in the scope of the closure:$coefficient = 2; $arr = [1,2,3,4]; $new_arr = array_map(function($e) use ($coefficient) { return $e * $e * $coefficient; }, $arr); print_r($new_arr); //[2,8,18,32]This PHP 7.4 code gets the same result using the arrow function – notice that we don’t need a “use” statement, and can access $coefficient directly in the short closure:<?php $coefficient = 2; $arr = [1,2,3,4]; $new_arr = array_map(fn($e) => $e * $e * $coefficient, $arr); print_r($new_arr); //[1,4,9,16]Coalescing Assign OperatorsThe coalescing assign operator in PHP 7.4 can save you time and simplify your code. It assigns the value on the right of the operator to the left parameter, if that parameter’s value is null. Otherwise, the value of the parameter remains the same. One of the most common use cases for this is when you’re importing variables from the super global variables and want to check if the value was passed, otherwise provide a default value.The following example shows how you can improve code simplicity by comparing like statements written in using releases prior to PHP 7, PHP 7.x releases before PHP 7.4, and PHP 7.4 which uses coalescing assign operators: <?php //PHP < 7 $data['key'] = isset($data['key']) ? $data['key'] : 'some_default'; //PHP 7.X < 7.4 $data['key'] = $data['key'] ?? 'some_default'; //PHP >= 7.4 $data['key'] ??= 'some_default';Spread OperatorIt is now possible to use the spread operator in array expressions:$arr1 = [3,4,5]; $arr2 = [8,9,10];Before PHP 7.4, you would have to write the following to merge arrays together:$superArray = array_merge([1,2], $arr1, [6,7], $arr2);With PHP 7.4, you can write the same statement like so: $superArray = [1, 2, ...$arr1, 6, 7, ...$arr2];Numeric Literal SeparatorPHP 7.4’s numeric literal separator functionality makes it possible for you to improve code readability by adding underscores between digits in numeric literals. This really helps reading large numbers like 100 million, one billion, etc.For example, before PHP 7.4, you would write numbers like this:$threshold = 1000000000Now, with PHP 7.4, you can add numeric literal separators to make the value look like this:$threshold = 1_000_000_000Note that this is an improvement for readability only – the compiler will strip those separators out when compiling the code.Engine ChangesPHP 7.4 includes improved engine functionality, including:Typed propertiesCovariant returns and contravariant parametersCustom object serializationTyped PropertiesIn PHP 7.4, class properties can be typed. Here is an example of how you can used typed properties, private and public, in a class called BankAccount: <?php class BankAccount { private int $id; private Money $balance; }Covariant Returns and Contravariant ParametersPHP releases prior to 7.4 supported invariant return types and parameter types, which meant that methods in a class implementing an interface or inheriting from another class had to return a value of the same type as the return value of methods that they override or implement. Similarly, method arguments had to be of the same type as the methods that they override or implement.In PHP 7.4, they can be different, which is useful in many scenarios. However, for return types, the return value of a method in the child class must be more specific than the return value of the method being overridden or implemented in the parent class or interface (covariant), and for method arguments in the child class they must be less specific than the method arguments being overridden or implemented in the parent class or interface.Here is an example of a covariant return:<?php interface Factory { public function make(): object; } class UserFactory implements Factory { public function make(): User; }Here is an example of contravariant parameters:<?php interface Concatable { public function concat(Iterator $input); } class Collection implements Concatable { // accepts all iterables, not just Iterator public function concat(iterable $input) {/* . . . */} }Custom Object SerializationTwo new custom object serialization methods are available in PHP 7.4: _serialize() and _unserialize(). These were added on top of the existing _sleep()/_wakeup() and Serializable interface mechanisms.These two functions were added to solve some issues that both the __sleep()/__wakeup() mechanism and the Serializable interface mechanism had. Consider the following code snippet:<?php class A implements Serializable { private $prop; public function serialize() { return serialize($this->prop); } public function unserialize($payload) { $this->prop = unserialize($payload); } } class B extends A { private $prop; public function serialize() { return serialize([$this->prop, parent::serialize()]) } public function unserialize($payload) { [$prop, $parent] = unserialize($payload); parent::unserialize($parent); $this->prop = $prop; }In this example:On serialize: A::serialize() is called, then B::serialize() is called.On unserialize B::unserialize() then A::unserialize() is called.This makes is so back references created during serialization will no longer be correct during unserialization.There were also some other issues:Executing code in the middle of serialization is dangerous.It has led to many vulnerabilities in the past.wakeup() calls are delayed until the end of serialization.First, the whole object graph is constructed — and then queued __wakeup() calls are executed.Former methods then see objects before they are fully unserialized => unsafe.There is no general way to analyze serialized strings.This is because serialize can return data in an arbitrary format.Now consider this code snippet with the new __serialize()/__unserialize() functions: <?php class A { private $prop_a; public function __serialize(): array { return ["prop_a" => $this->prop_a]; } public function __unserialize(array $data) { $this->prop_a = $data["prop_a"]; } } class B extends A { private $prop_b; public function __serialize(): array { return [ "prop_b" => $this->prop_b, "parent_data" => parent::__serialize(), ]; } public function __unserialize(array $data) { parent::__unserialize($data["parent_data"]); $this->prop_b = $data["prop_b"]; } }Notice that instead of calling serialize()/unserialize(), the method directly returns the serialized object in an array, and unserialize() only accepts an array as its argument.Class PreloadingClass preloading gives developers the ability to specify the files that get compiled at PHP startup, which can be useful in many situations, one of which is to preload framework files. However, if these files change, the server must be restarted.To use this feature, pass a file path to the opcache.preload directive in php.ini: opcache.preload=/path/to/project/preload.phpIn it, you must call opcache_compile_file(...) or require_once(...) for every file you want cached.There are a few caveats to class preloading:Unlinked classes can’t be preloaded. Dependencies, interfaces, traits, and parent classes must also be preloaded.If an attempt is made to load an unlinked class, the compiler issues a warning. It will still work. However, all the classes won’t be preloaded.require_once can be used to rely on the autoloader to load all the dependencies, traits, interfaces, and parent classes.For more information on class preloading, see https://stitcher.io/blog/preloading-in-php-74.FFIThe Foreign Function Interface (FFI) API has existed for years in languages Python and LuaJIT. In PHP 7.4, it is a new extension that provides a simpler way to call native functions and access native variables. FFI can be used to include external libraries written in C with relative ease and allows for rapid prototyping without having to write a complete extension. To use PHP FFI, you need to provide a header (.h) file with the functions that you want to expose through FFI, and then load the shared library that implements them with FFI::load(). Once you do that, functions and data structures defined in the .h and implemented in the shared library become accessible inside your PHP script through the FFI object.You can learn more about the FFI API in these resources: https://www.php.net/manual/en/ffi.examples-basic.phphttps://www.zend.com/blog/php-foreign-function-interface-ffihttps://blog.remirepo.net/post/2019/10/23/FFI-extension-usage-with-PHP-7.4https://github.com/dstogov/php-tensorflowDeprecations and Other Language ChangesPHP 7.4 introduces some additional changes that are important to know about. Let’s start with deprecations. Most, if not all, programming languages use a right-associative ternary operator. However, PHP uses left-associative, which can be confusing for developers. Starting with PHP 7.4, a deprecation warning will result for the following code unless parentheses are used:1 ? 2 : 3 ? 4 : 5; // deprecated (1 ? 2 : 3) ? 4 : 5; // okIn PHP 8, deprecation will become a compile time error. Here’s a quick summary of the other changes in PHP 7.4:Exceptions are now allowed in _toString(). They were previously prohibited because of a vulnerability.The array_merge function can be called without arguments or any parameter, where formerly one parameter was required. This is to support usage of the spread operator, and the edge case where a parameter passed to array_merge might be empty.Upgrades were made to proc_open() so it can execute programs by passing an array instead of a string, and without going through a shell. Back to topLearn More About PHP 7.4Want to learn more about the new features in PHP 7.4? Watch my one-hour recorded webinar, titled: PHP 7.4 Is Here! Learn What’s New.Watch WebinarAdditional ResourcesResource Collection - Exploring PHP VersionsBlog - Planning for PHP 7.4 EOLBlog - Use PHP 7 or PHP 5? Get the Long Term Support That You Need Blog - PHP Development: Using PHP Extensions blogTechnical Guide - Writing PHP Extensions technical guideResource Collection - Developing Web Applications with PHP hubBlog - Managing Security Risks in the PHP Engine and Web Applications Back to top