DEV Community

Pete McFarlane
Pete McFarlane

Posted on

Exploring PHP8 new goodies - match expression

It's here, just in time for Christmas! I'm not sure how many will be using PHP8 in production this year, but that's not to say many of us aren't already trying it on smaller side projects to get a taste of some of the new features.

My favourite so far, the new match() expression.

Many other programming languages including Haskell, Erlang, and Elm, have a similar feature, but previously PHP only had the switch statement.

The switch statement is fine, but you have a few things to be mindful of.

Firstly a switch doesn't return a value, it's not an expression, although you can return early from a switch statement

switch ($operation) {
    case 'nop':
        return $this->nop();
    case 'acc':
       $this->acc($argument);
    case 'jmp':
       return $this->jmp($argument);
}
Enter fullscreen mode Exit fullscreen mode

https://github.com/petemcfarlane/advent-of-code-2020/blob/8f5cc97377e2313e7fcbf60fb739e8084b01025e/day8/index.php

With a match this becomes much terser

return match ($operation) {
    'nop' => $this->nop(),
    'acc' => $this->acc($argument),
    'jmp' => $this->jmp($argument),
};
Enter fullscreen mode Exit fullscreen mode

It's also easier to prevent mistakes, like forgetting to return on the "acc" branch in the previous switch example.

A match can match multiple values, if they are comma separated, so I could write the above as

return match ($operation) {
    'nop' => $this->nop(),
    'acc', 'jmp' => $this->{$operation}($argument),
};
Enter fullscreen mode Exit fullscreen mode

Although in this case I'm not sure it's particularly easier to read.

There is a default branch you can use if you want to specify what should be returned if there is no match. You can also use arbitrary functions for comparisons in the match conditions.

function validateEmail(string $email): string
{
    return match (true) {
        str_contains($email, '@example.com') => 'an example email',
        $email === filter_var($email, FILTER_VALIDATE_EMAIL) => 'a valid email',
        default => throw new InvalidArgumentException('Invalid email address')
    };
}

var_dump(validateEmail('hello@example.com')); // returns 'an example email'
var_dump(validateEmail('foo@bar.com')); // returns 'a valid email'
var_dump(validateEmail('invalid email')); // throws InvalidArgumentException
Enter fullscreen mode Exit fullscreen mode

In this example I'm also taking advantage of being able to throw exceptions in

We also get a new UnhandledMatchError if we forget to declare a path. This can be somewhat useful, like the PHP7 TypeError, as the exception includes the type of value we tried to match, but not the value itself.

It would be really cool to be able to do partial matches or some kind of destructuring in the future, not sure if this going to be at all possible, something like

class A {
    public function __construct(public int $n) {}
}

class B {
    public function __construct(public int $n) {}
}

$x = new A(1); // or new B(2);

match ($x) {
    new A($n) => $n,
    new B($n) => $n,
};

Enter fullscreen mode Exit fullscreen mode

Top comments (0)