loading...
Cover image for What's new in PHP 8 and what does that mean

What's new in PHP 8 and what does that mean

jopacicdev profile image Josip Opačić ・4 min read

Photo by Larry Li on Unsplash

The official General Availability date for PHP 8 is November 26th, 2020 which will be when all the new and shiny features are stable and available. While this article is being written during the Alpha phase, and before the Feature Freeze, the content may be updated. Here's a rundown of the most interesting new features and what do they mean for us!

Attributes

Attributes are, hands down, the biggest addition to PHP. Attributes help add metadata to functions/parameters/classes/methods/constants/properties etc -- what was previously simulated via docblocks, and then parsed elsewhere. Attributes are now first-class citizens in PHP, and can be accessed programmatically!

@@Route(Http::POST, '/store/123/item')
class ItemCreateHandler
{
    public function __invoke() {
        // ...
    }
}

It's notation is still unfolding -- going from <<FooAttribute>> to @@FooAttribute, and Derick Rethans challenging the whole thing with a simple 'Are we reaaaaaly sure?' question, proposing Rust-like #[FooAttribute]:

There are signs that there might even be a RFC during the Feature Freeze period. Either way, there's no denying that attributes are a welcomed feature! If you'd like to read an in-depth analysis, check here and here.

Constructor property promotion

Simple argument-to-property assignment, your days are numbered! There were quite some times that all of us written (almost) the same constructor over and over:

class Response {
    private int $code;
    private string $body;
    private array $headers;

    public function __construct(int $code, string $body, array $headers) {
        $this->code = $code;
        $this->body = $body;
        $this->headers = $headers;
    }
}

... you get the idea. Well, it's a wee bit easier. What does that mean? Here's how it could be written:

class Response {
    public function __construct(
        private int $code,
        private string $body,
        private array $headers,
    ) {}
}

Neat! The assignment happens before the constructor code is executed. You can absolutely mix constructor promoted properties with standard props (please don't).

There are some limitations, you can check them out here.

match expression

How many times have you written line-intensive switch expressions, just to end up with a kraken devouring your viewport? Here's a good example:

switch ($x) {
    case 1:
        $y = 3;
        break;
    case 2:
        $y = 4
        break;
    case 3: case 4:
        $y = 5;
        break;
    ...
    default:
        throw new \RuntimeException('Not happening, bud');
} 

What does this mean? Well, now we can write it more readably.

$y = match ($x) {
    1 => 3,
    2 => 4,
    3, 4 => 5,
    ...
    default => throw new \RuntimeException('Not happening, bud'),
}

It's important to note the new match expression now returns a value, so it's unnecessary to repeat the assignment throughout your cases.

Probably inspired by ES6 to look a bit more modern each matching case contains only one expression, and also a break is implicit - so the condition won't just fall through as in switch.

Union Types

The next feature should come in handy since PHP is a dynamically typed language. Union types allow you to specify 2 or more acceptable types for an argument or return type. PHP already supports two special union types (Type or null using the special ?Type syntax; and array or Traversable using the iterable type).
Now, instead of handling types with phpdoc annotations, the following could be used:

class Number {
    private int|float $number;

    public function setNumber(int|float $number): void {
        $this->number = $number;
    }

    public function getNumber(): int|float {
        return $this->number;
    }
}

As you might be familiar with ? to represent nullable, you could also use null:

public function handle(Product|null $product): int
// equals
public function handle(?Product $product): int

For more information about nitty-gritty details and it's limitations, read it's RFC by Nikita Popov.

Named Arguments

Named arguments allow passing arguments to a function based on the parameter name, rather than the parameter position. Here's a quick example:

// Positional arguments
json_encode($data, 0, 512);

// Named arguments
json_encode(value: $data, options: 0, depth: 512);

I'll let you pick which one you like more.

Named arguments allow you to skip default values:

json_encode(value: $data, depth: 256);

You can mix unnamed ones with named ones:

json_encode($data, depth: 256);

But if you wrongly pass an ordered argument after a named one, it will throw an error:

// This code will throw
json_encode(depth: 256, $data);

There is more to it, such as how you can enrich your DTOs or VOs with it using spread operator, how you can use Named Arguments with Attributes, etc -- I strongly suggest that you read and enjoy the RFC!

Use ::class on objects

How many times have you thought "ow wouldn't it be nice if I could $a::class..."? Well, now you can. It accomplishes the same thing as get_class, but I prefer it ¯\_(ツ)_/¯

get_class($a) === $a::class;

Be aware that it will trigger a fatal error on PHP versions lower than 8; and that non-objects cannot use the ::class notation.

What does this mean

The community welcomes most of the changes -- (see: Attributes notation as an exception), but I have a feeling that the new version brings in good change. The way we write PHP code is getting a facelift!

Posted on by:

jopacicdev profile

Josip Opačić

@jopacicdev

Laravel developer and enthusiast, code lover since my first Commodore 64!

Discussion

markdown guide
 

That's funny. I wrote a lot of PHP in the past, and I follow its development. The language appears more and more weird to me.

I don't see any real value of most of this. It looks just messier. What's the problem of writing a constructor? Especially since you can just use snippets in your editor. Same with switch cases.

Union types would be nice if typing wasn't that... unpredictable without strict types.

Maybe it's just me.

 

Totally agree. Changes are not bad, they're just all over the place and bring nothing valuable.

 

Seems great at first glance. I was wondering, for the Construction Property Promotion, there is every so often some private setters for validation I will create. Would it be possible to call them at that level or I will need to call them in the constructor like before?

 

Finally adding some of the features I've loved about Python ;)

The annotation feature is huge because parsing docblocks to generate code is awkward and slow. Frameworks like Symfony should see huge performance gains at "build" time or during first load. Also means the PHP runtime can finally throw meaningful warnings or errors before the code executes.

 

Really nice and very helpful
Thank you so much

 

Excited to see how writing Laravel code will evolve with all these changes.

 

Amazing article and very nice update by php thanks for sharing it

 

congrats on the first post-Great Article

 

I feel constructor property promotion and union types are going to be the hot new thing out of all of these new features, the attributes feel so so, could live without them, to be frank.

 

Helpful post with a lot of explanation.
Thank you.