PHP 8 New Features [What you need to know]

Coding (PHP 8)


Discover all the new improvements, syntax fixes and new features of PHP 8
 
/img/blog/php-8-new-features-syntax-changes.jpg

Introduction

 

A few days ago, I came across an article explaining the new characteristic of the upcoming Playstation 5.

 

Of course, the article was describing the new design and what type of integrated circuit they have added and why.

 

I am not an eager player, so did not care much about the new advanced super-fast chips or the almost terabyte of storage available,

 

but I was interested in reading the reaction of the people in the comment section.

 

There is no doubt the people at Sony have created a product that has changed people lives,

 

allowing them to live thousands of different adventures or live in the shoes of their sports heroes, war veterans etc.

 

And it was while reading these comments about what new games the users are going to play that I thought that something similar is about to happen in the PHP community.

 

In a few weeks, PHP 8 is going to be released and thanks to its new features it will let our imagination and skill create new amazing applications even with more ease than the previous version did.

 

In this article, we are going to dive into all the new features included and explain what the are and how to use them for the best

 

 

Become a Patron!

 

 

A look into PHP 8 the series

 

The goal of this series is to get you ready to work with the latest version of this beautiful backend language.

 

The episode of the series are (in chronological order):

  • September's updates the collection of all the most important features and changes a month before they arrive at our machine 
  • New Features the list with explanation of all the new toys we will have in our arsenal
  • Changes Discover all the new improvements, syntax fixes and new features of PHP 8
  • JIT We have heard about JIT for a long time and it almost among us, learn all there is to know about it

 

Table of Content

 

Timeline
New features
    Syntax
        str_contains

        str_starts_with

        str_ends_with

        fdiv

        get_debug_type

        get_resource_id

        Union types

        Named arguments

        nullsafe operator

        Attributes, commonly known as annotations

        Constructor property promotion

        New mixed type

        Trailing comma in parameter lists 

    Operations

        JIT

        ext-json always available 

        Match expression

    Behaviours

        Throw expression

        New static return type 

        Alternative to get_class()

        Inheritance with private methods

        Weak maps

        Non-capturing catches

        Create DateTime objects from interface

        New Stringable interface

        Abstract methods in traits improvements

        implementation of token_get_all
Changes

    Consistent type errors

    Reclassified engine warnings

    The @ operator no longer silences fatal errors

    Default error reporting level

    Default PDO error mode

    Concatenation precedence

    Stricter type checks for arithmetic and bitwise operators

    Namespaced names being a single token

    Saner numeric strings

    Safer string to number comparisons

    Reflection method signature changes

    Stable sorting

    Fatal error for incompatible method signatures

 

 

 

New features

 

Syntax

 

nullsafe operator

 

More often than not, it happens that I needed to call a method only if the result of expression was different than null.

 

To understand what I mean have a look at the following code:

$country = null;

if ($session !== null) {
    $user = $session->user;

    if ($user !== null) {
        $address = $user->getAddress();

        if ($address !== null) {
            $country = $address->country;
        }
    }
}

 

The code works but in order to get the country I have to do several checks and to get the value I want I have to hope that all the variables do not equal to true.

 

If according to the code above, the $address variable is null I have done several calculations with no result at all.

 

Not to mention my code now looks incredibly ugly.

 

That is basically breaking rule #1 of Object Calisthenics: Only One Level Of Indentation Per Method

 

Ilija Tovilo proposed an RFC to fix that, and the way it will be fixed is by a new operator

 

the new nullsafe operator ?-> with full short-circuiting

 

With PHP 8 it will be possible to refactor the code above with something way nicer like the snipped below:
 

$country = $session?->user?->getAddress()?->country;

 

What this code does is to check every single variable starting from the left, thus the $session then moves step by step to the country one.

 

If one of the variables is null, then the entire line returns a null value to the $country variable otherwise $country gets the value of the last element of the chain.

 

This operator includes short-circuiting.

 

In programming, Short-circuiting means the practice of skipping the evaluation of expression as we saw above depending on some condition.

 

A more common example that you have seen are the operators && (AND) and || (OR).

 

If you do not know what I am talking about, my advice is to check the Basics of PHP here then come back to this article.

 

Here is the official RFC

 

 

Attributes, commonly known as annotations

 

 

You may have noticed that during the last few years one of the 'trend' among PHP developer is the one of using PHPdocs,

 

I know of some working places in which pull requests will not be accepted if the new methods do not have doc-comments on top of them.

 

These comments even though useful, they are not officially integrated into the language.

 

In fact, several other languages consider this a fundamental part of the core.

 

And, confusing enough each programming language changed the name of this feature.

 

They are known as Annotations in Java, Attributes in C#, C++, Rust, Hack and Decorators in Python, Javascript.

 

The proposal by Benjamin Eberlei is the implementation of text enclosed with "<<" and ">>" 

 

These additions can be used over functions (including closures and short closures), classes, interfaces, traits, constants, properties, methods as well as method parameters.

 

Here are a few examples of attributes in PHP

 

<>

class Foo
{
    <>
    public const FOO = 'foo';

    <>
    public $x;

    <>
    public function foo(<> $bar) { }
}

$object = new <> class () { };

<>

function f1() { }

$f2 = <> function () { };
$f3 = <> fn () => 1;

 

As you can see, the attributes are added just before the declaration they belong to, exactly like the doc-block comments. 

 

Among the characteristics of these attribute, there is the fact that attributes may have values associated with it and the elements of the code can have one or more attributes.

 

<>
<>
<>
function SayHello() {}

 

There are 2 RFC for this feature the first one is Attributes v2 the second one Attribute Amendments.

 

 

Constructor promotion

 

Until PHP 8 if you wanted to create value objects, I talk about them in a domain-driven design post, you need to use some boilerplate code.

 

Just look at the example below:

 

class Age {
    public float $age;

    public function __construct(
        int $age = 0
    ) {
        $this->age = $age;
    }
}

 

We simply want to add an Age value object in our application, but we are forced to refer to the $age variable four times.

 

The implementation, initially raised by Nikita Popov, helps us avoid this repetition.

 

The way the code is going to improve is by combining the properties definition and the constructor.

 

class Age {
    public function __construct(
        public int $age = 0
    ) {}
}

 

 

Way better!

 

There are three main constraints with this new feature

 

  • The new code has to be within a constructor;
  • It cannot be inside an abstract constructor;
  • And it cannot be inside the constructor of an interface;

 

The Mixed type

 

This is a polarizing new feature that will make half of the PHP programmers happy but will also leave a bad feeling on the other half.

 

Since the arrival of PHP 7, the community and the core developer have always moved toward making this language less and less loosely typed.

 

It means that you can change the type of variables on the fly.

 

This, for some, has the downside of making the code less clear and more prone to bugs.

 

It is also true though that plenty of developers do not have any problem with that, in fact, they will rather use a loose type style of coding until they are allowed to do so.

 

For this reason, from PHP 8 onwards, we will be able to use another type.

 

The mixed type is being added to the family, and he represents many other types.

 

  • array
  • bool
  • callable
  • int
  • float
  • null
  • object
  • resource
  • string

 

 

Before PHP 8, you could only use mixed inside PHPDoc-based type hints to provide some context about a variable.

 

Now you can actually type-hint a parameter using this type.

 

class Player
{
    public function setAction (mixed $value) {}
}

 

In the above example, we can use different types of variables of our $value parameter.

 

Note that if a parameter cannot be narrowed from mixed PHP will throw a fatal error.

 

class Car
{
    public function start (mixed $value) {}
}

class Fiat extends Car
{
    public function start (int $value) {}
}

 

Of course, it is ok to do the opposite.

 

Allow a trailing comma in the parameter list

 

This is just a syntax fix that makes the code a bit more readable.

 

At the moment if you have many parameters in a method, you would likely do something like the following.

 

class Person {
    private function __construct(
        string $name,
        string $surname,
        string $height,
        string $weight,
        int $age,
        string $favSport,
        string $location,
        string $nationality
    ) {
        ...
    }
}

 

In this case, if you want to add another parameter (what, another?) you must remember to add the trailing comma too.

 

As per array, it would be now possible to add a comma at the end of the last parameter without throwing an error.

 

class Person {
    private function __construct(
        string $name,
        string $surname,
        string $height,
        string $weight,
        int $age,
        string $favSport,
        string $location,
        string $nationality,
    ) {
        ...
    }
}

 

Operations

 

Match expression

 

In my humble opinion, this is huge, and it will change the way we learn the basics of PHP for a while.

 

In every 101 books of PHP, you are going to read about the switch statement.

 

The new match expression may be something that will substitute it.

 

This is a normal switch case as we have seen a thousand of them already.

 

switch ($type) {
    case 'sedan':
        $sentence = 'this is a senad';
        break;

    case 'minivan':
        $sentence = 'this is a minivan';
       break;

    case 'station wagon':
        $sentence = 'this is a station wagon';
        break;

    default:
        $sentence = 'this is a car';
        break;
}

 

Easy right?

 

With the implementation of the match, we can simplify the syntax and use this instead.

 

$sentence = match ($type) {
    'sedan' => 'this is a sedan',
    'minivan' => 'this is a minivan',
    'station wagon' => 'this is a station wagon',
    default => 'this is a car',
};

 

Conditions can be combined, there is no need for remembering to use the break operator.

 

Overall it is way simpler to use it.

 

Remember that the match expression uses strict comparison (===) instead of loose one like the switch. 

 

Read Strict vs. Loose Comparisons in PHP to understand the differences

 

The comparison is strict regardless of strict_types.

 

Behaviours

 

Remove inappropriate inheritance signature checks on private methods

 

As you can imagine, on the background PHP runs several checks that allow it to find errors and problems with your code.

 

One of these checks consists in verifying if there is any inheritance between a method and its parent’s namesake.

 

This makes a lot of sense because in this way we can override the behaviour of a method according to the concrete class we are working on.

 

Problem is: it makes sense 66% of the time.

 

As you know in Object-oriented PHP there are 3 types of visibility.

 

They are public, protected and private.

 

Here is a full explanation of the concept of visibility on OOP.

 

While this check is perfectly fine in the case of public or protected, it is just a waste of type if operating on private methods.

 

Because they can only be available inside the class itself.

 

Currently, you will get this error if you try.

 

class IceCream
{ 
    final private function make() { 
        echo 'this method make me hungry'; 
    } 
} 

class Cone extends Icecream
{ 
    private function make() { 
        echo 'this method make me hungry too'; 
    } 
}

 

Fatal error: Cannot override final method IceCream::make()

 

From PHP 8 onwards, the core language is removing these inheritance checks contributing to making the language a bit faster.

 

As a side note of this feature, a warning has been introduced when you create a final private class like in the example above.

 

Look the example below:

 

final private function make() { 
    echo 'this method make me hungry';
} 

 

Warning: Private methods cannot be final as they are never overridden by other classes

 

Weak maps

 

Last year you read about the new implementation of Weak References, they were good additions to the code but, as I have written then, their use cases it is pretty limited.

 

In PHP 8, we have Weak Maps which allow us to create a map of objects without preventing objects, used as keys, to be garbage collected.

 

If a key (under the form of an object) is collected, it will be removed from the map.

 

$map = new WeakMap;
$obj = new Phone;
$map[$obj] = ‘S3’;
var_dump($map);
// object(WeakMap)#1 (1) {
// [0]=>
// array(2) {
// ["key"]=>
// object(Phone)#2 (0) {
// }
// ["value"]=>
// string(2)
// }
// }

// The object is destroyed here, and the key is automatically removed from the weak map.
unset($obj);
var_dump($map);
// object(WeakMap)#1 (0) {
// }

 

You can use weak maps to associate data with object instances, even when these objects are not ‘alive’ anymore, this means you prevent leak memory in long-running processes.

 

For more info about WeakMap you can refer to Mahdhi Rezvi' article Understanding WeakMaps in JavaScript.

 

Support for anonymous catches

 

Support for anonymous catches is a feature wanted for several years,

 

The first proposal for it is dated 2013.

 

And it solves a quite simple but relevant problem

 

It is common practice that when you test your code, you use try/catch blocks like this one.

 

try {
    MakePizza();
} catch (Exception $e) {
    die(‘you tried to use pineapple as topping’);
}

 

The problem with this code is that you have to specify a variable even if you do not want to use it.

 

The proposal by Max Semenik is to avoid creating the variable and save space in memory.

 

try {
    MakePizza();
} catch (Exception) {
    die('you tried to use pineapple as topping');
}

 

Create DateTime and DateTimeImmutable objects from interface

 

DateTime and DateTimeImmutable classes implement DateTimeInterface

 

Until PHP 7.4 it was possible to create an object from one another in this way.

 

  • DateTime::createFromImmutable(DateTimeImmutable $immutable): DateTime
  • DateTimeImmutable::createFromMutable(DateTime $date): DateTimeImmutable

 

Now there is a new method in both classes that allow their creation depending on the interface instead.

 

This means that you can now create an object, but the new method accepts any DateTimeInterface implementation.

 

  • DateTime::createFromInterface(DateTimeInterface $object): DateTime
  • DateTimeImmutable::createFromInterface(DateTimeInterface $object): DateTimeImmutable

 

Add Stringable interface

 

The first purpose of this implementation is to allow using the string|Stringable type in PHP 8.

 

Consider the following function.

 

class Product
{
    // constructor and setter here

    public function __toString(): string
    {
        return $this->name;
    }

    public function getName(): string
    {
        return $this->name;
    }
}

function storeProductInDb(string $name) { 
    echo $name . 'saved in db';
}

$product = new Product();
$productName = $product->getName(); 
storeProductInDb($productName);

 

Right now, if I want to save a product into the db, I am only limited to using its name.

 

As you can see, the class includes a toString, learn about  __toString() magic method in here.

 

What this proposal adds to PHP is the possibility to add the Stringable as a type hint.

 

In this way, you could do this instead.

 

class Product
{
    // constructor and setter here

    public function __toString(): string
    {
        return $this->name;
    }
}

function storeProductInDb(string|Stringable $name) { 
    echo $product . 'saved in db';
}

storeProductInDb(new Product());

 

 

How cool is that,

 

Just saved a lot of time plus the code is way more readable.

 

 

Validation for abstract trait methods

 

It is weird to say, but after 2 decades there are still strange things happening in the core PHP.

 

Have a look at the code below.

 

trait Shareable {
    abstract public function share(int $x): bool;
}  

class BlogPost {
    use Shareable;
    public function share(string $x) {}
}

 

Do you see anything wrong with this code?

 

Well, in the trait the parameter accepted is an integer in the concrete class it is a string.

 

The problem is that this is actually allowed in PHP 7.4, it is so because trait method signatures are currently not enforced.

 

From PHP 8 that is going to change,

 

Here is how.

 

trait Shareable {
    abstract public function share(int $x): bool;
}  

class BlogPost {
    use Shareable;

    // This is allowed:
    private function share(int $x): bool { }

    // This is forbidden (incorrect return type)
    private function share(int $x): stdClass { }

    // This is forbidden (non-static changed to static)
    private static function share(int $x): string { }
}

 

According to the way the language is going, loose typing is going to be seen less also this little enhancement helps to keep the process that way.

 

Object-based token_get_all() alternative

 

Various parts of the PHP language are represented internally by types like T_SR.

 

PHP outputs identifiers like this one in parse errors, like "Parse error: unexpected T_FUNCTION, expecting ',' or ';' in script.php on line 10."

 

These are called PHP tokens,

 

You can find a list and explanation of all the tokens in the official documentation.

 

If you want to check all the tokens in a given script, you use the token_get_all() function.

 

As shown below.

 

$tokens = token_get_all('');

foreach ($tokens as $token) {
    if (is_array($token)) {
        echo "Line {$token[2]}: ", token_name($token[0]), " ('{$token[1]}')", PHP_EOL;
    }
}

Line 1: T_OPEN_TAG ('')

 

Currently, this function returns either a single-character string or an array with a token ID, 

 

token text and line number. 

 

From PHP 8 you can use a new PhpToken class as well.

 

The way you would use it is by doing the following.

 

class MyPhpToken extends PhpToken {
    public function getLowerText() {
        return strtolower($this->text);
    }
}

// getAll works the same as token_get_all(), but returns array of PhpToken
$tokens = MyPhpToken::getAll($code);
var_dump($tokens[0] instanceof MyPhpToken); // true
$tokens[0]->getLowerText();

 

The PhpToken::getAll() method replaces token_get_all(), which returns an array of PhpToken objects instead of a mix of strings and arrays.

 

 

 

 

 

 

 

Conclusion

 

I know, I know.

 

There is a lot to take on in this post,

 

The fact is that PHP 8 will represent a milestone for every web developer interested in the language.

 

As you can see from these features, we keep moving toward the direction of more readability and type tightening. 

 

This is good, 

 

Eventually, it will lead to less error in the code and straightforward interchangeability with other backend languages.

 

It means that plenty of Perl, Ruby, Python, and Self developers will have an easier life when trying to code in PHP.

 

Also, PHP 8 promises to become one, if not the fastest, backend language at all, so it is good to know what tools are available in your toolbox.

 

Also plenty of new syntaxes updates, new core class and interface.

 

My goal with this post is to make you aware of what is going on in the PHP environment and I am doing so by providing you with the best content and explanation as possible.

 

Also, the next chapter of this series is already on its way.

 

If you want to learn more about this topic, subscribe to the newsletter and be the first to be notified when I publish a new article.

 
 
If you like this content and you are hungry for some more join the Facebook's community in which we share info and news just like this one!

Other posts that might interest you

Coding (PHP 8) Sep 9, 2020

PHP 8 New Features [September's updates]

See details
Coding (PHP 8) Oct 1, 2020

PHP 8 Changes [what is next?]

See details
Coding (PHP 8) Oct 19, 2020

PHP 8 JIT [most expected feature]

See details
Get my free books' review to improve your skill now!
I'll do myself