PHP 7.4: what is new in PHP

After more than a year after the last minor version of PHP, the time has come for a new release.

While previous minor versions of PHP mostly focused on performance improvements, but this one is fully focused on new features and syntax improvements. All in all, PHP 7.4 gives us the largest number of new features since its last major release which happened almost 4 years ago.

With 7.4, some features that were already implemented in other modern object-oriented programming languages finally came to PHP. While some of them will have a bigger impact on your codebase, others will be mostly used under the hood of your framework. In this blog, we will go through some of the most important new features and show examples for each of them.

Typed properties

The long-anticipated feature of typed properties is finally implemented into the core. This should improve the overall strictly typed patterns in the language and improve the readability of your code. Until now, we used PHPDoc annotations to fulfil this feature, but from now on, a more natural way can be used. All PHP types are accepted with the exception of void and callable.

class Post
{
     public string $title = 'PHP 7.4';
     public string $content = 'Lorem ipsum dolor sit amet.';
}

If we change the title value to an integer, this will produce a fatal error.

class Post
{
     public string $title = 1;
     public string $content = 'Lorem ipsum dolor sit amet.';
}

But even if this sounds fairly straight-forward, we have some ‘gotchas’ here with strict and coercive typing modes. If strict_types=1 at the location of property write, then the value of exactly the same type must be provided. But if strict_types=0 at the location of property write, then the usual rules for coercive type checks are followed.

class Post
{
    private string $title;
    private string $content;
 
    public function __construct($title, $content)
    {
        $this->title = $title;
        $this->content = $content;
    }
 
    public function getTitle(): string
    {
        return $this->title;
    }
 
    public function getContent(): string
    {
        return $this->content;
    }
}
 
new Post(1, 'Lorem impsum'); // 1 will be casted to string when strict_types=0 

In combination with strictly typed function parameters like getters and setters, this could drastically reduce bugs with type inconsistency which, until now, could be detected only with a third-party tool like PHPStan.

Arrow functions

The introduction of arrow functions is another big feature in this release. Arrow functions shorten the syntax of writing callables with some useful extra features. Before 7.4, we used anonymous functions that had a syntax similar to classic functions, but with the extra keyword “use” when variables from parent scope needed to be inherited by an anonymous function.

$even = false;
$numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
$remainder = $even ? 0 : 1;


$filteredNumbers = array_filter($numbers, function (int $number) use ($remainder) {
    return $number % 2 === $remainder;
});


print_r($filteredNumbers); // returns [2, 4, 6, 8, 10]

By using the arrow function, we now have a cleaner syntax that uses the new reserved keyword “fn” with implicit by-value scope binding.

$even = false;
$numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
$remainder = $even ? 0 : 1;
 
 
$filteredNumbers = array_filter($numbers, fn (int $number) => $number % 2 === $remainder);
 
 
print_r($filteredNumbers); // returns [2, 4, 6, 8, 10]

Exceptions in __toString

Until now, it was impossible to throw exceptions from __toString magic method. Now, this is possible – just like in any other place. It will also no longer result in a fatal error (except when exceptions are not handled properly).

public function __toString()
{
     if ($this->id > 10) {
          throw new Exception('Exception from __toString');
     }
     return ''; 
}

Null coalescing assignment operator

In this release, there is also a new operator which tries to replace the old syntax, where we check if a variable is equal to null and then set it to some different value.

if ($user === null) {
    $user = 'PHP';
}

This can now be shortened to the new syntax.

$user ??= 'PHP';

Unpacking inside arrays

Spread operator was already widely used in some other programming languages, and is now added to PHP. Before the spread operator, PHP used the array_merge function which could still be useful in some situations described below.

$oddNumbers = [1, 3];
$evenNumbers = [2, 4];
$numbers = array_merge($oddNumbers, $evenNumbers);
print_r($numbers); // returns [2, 4, 1, 3]

We can now accomplish the same result by using the spread operator.

$oddNumbers = [1, 3];
$numbers = [2, 4, …$oddNumbers];

print_r($numbers); // returns [2, 4, 1, 3]

When using the spread operator with indexed arrays, there is no difference from array_merge, but using it with associative arrays could produce strange results.

If we try to unpack one array to another, following will start from the biggest incremented key value of the first array.

$oddNumbers = [
    1 => 'One',
    3 => 'Three',
];
$numbers = [
    2 => 'Two',
    4 => 'Four',
    …$oddNumbers
];
print_r($numbers); // [2 => ‘Two’, 4 => ‘Four’, 5 => ‘One’, 6 => ‘Three’]

This is very different from array_merge where the result will be na indexed array starting with index 0 ignoring keys from provided arrays.

$oddNumbers = [
    1 => 'One',
    3 => 'Three',
];
$evenNumbers = [
    2 => 'Two',
    4 => 'Four',
];
$numbers = array_merge($oddNumbers, $evenNumbers);

print_r($numbers); // [0 => ‘Two’, 1 => ‘Four’, 2 => ‘One’, 3 => ‘Three’]

The spread operator will produce a fatal error if the unpacking array contains string keys, when on the other hand array_merge will successfully merge it.

__serialize and __unserialize

These two new magic methods are added to provide a new serialization mechanism.

// Returns array with all nessery object data
public function __serialize(): array;

// Sets object state from data array
public function __unserialize(array $data): void;

This new mechanism replaces the Serializable interface, which is expected to be deprecated in future versions.

Weak references

Similar to other object-oriented languages like C# and Java, PHP also implemented weak references. A weak reference is a mechanism that allows the programmer to retain a reference to an object, while at the same time not preventing it from being destroyed. A most common use-case for weak references will be cache mechanisms.

$obj = new stdClass;
$weakref = WeakReference::create($obj);
unset($obj);
var_dump($weakref->get());

Conclusion

We are entering the new year with some useful and very important new features implemented in the PHP core. PHP in the current state and PHP in the future will move more towards the strictly-typed language – just like its main competitors. This should attract more people which didn’t favor it because of the lack of strict functionality within the core.

In addition to that, even more new features are in the RFC pipeline, or are already implemented and are waiting for a new major release, so we can be very excited to see what’s coming to PHP.