phpday 2022

match

(PHP 8)

La expresión match ramifica la evaluación basada en una comprobación de identidad de un valor. De forma similar a una sentencia switch, una expresión match tiene una expresión de sujeto que se compara con múltiples alternativas. A diferencia de switch, se evaluará a un valor muy parecido al de las expresiones ternarias. A diferencia de switch, la comparación es una comprobación de identidad (===) en lugar de una comprobación de igualdad débil (==). Las expresiones match están disponibles a partir de PHP 8.0.0.

Ejemplo #1 Estructura de una expresión match

<?php
$return_value 
match (subject_expression) {
    
single_conditional_expression => return_expression,
    
conditional_expression1conditional_expression2 => return_expression,
};
?>

Nota: El resultado de una expresión match no necesita ser utilizado.

Nota: Una expresión match debe terminar con un punto y coma ;.

La expresión match es similar a una sentencia switch pero tiene algunas diferencias clave:

  • Un brazo de match compara los valores estrictamente (===) en lugar de hacerlo de forma suelta como lo hace la sentencia switch.
  • Una expresión match retorna un valor.
  • Los brazos de Match no pasan a casos posteriores como lo hacen las sentencias switch.
  • Una expresión match debe ser completa.

Como las expresiones switch, las expresiones match se ejecutan de brazo a brazo. Al principio, no se ejecuta ningún código. Las expresiones condicionales sólo se evalúan si todas las anteriores no coinciden con la expresión del sujeto. Sólo se evaluará la expresión de retorno correspondiente a la expresión condicional que coincida. Por ejemplo:

<?php
$result 
match ($x) {
    
foo() => ...,
    
$this->bar() => ..., // bar() no se llama si foo() === $x
    
$this->baz => beep(), // beep() no se llama a menos que $x === $this->baz
    // etc.
};
?>

Los brazos de la expresión match pueden contener varias expresiones separadas por una coma. Se trata de un OR lógico, y es una abreviatura de múltiples brazos match con el mismo lado derecho.

<?php
$result 
match ($x) {
    
// Este brazo match:
    
$a$b$c => 5,
    
// Es equivalente a estos tres:
    
$a => 5,
    
$b => 5,
    
$c => 5,
};
?>

Un caso especial es el patrón default. Este patrón permite hacer coincidir cualquier cosa que no se haya hecho coincidir previamente. Por ejemplo:

<?php
$expressionResult 
match ($condition) {
    
1=> foo(),
    
3=> bar(),
    default => 
baz(),
};
?>

Nota: Múltiples patrones default lanzarán un error E_FATAL_ERROR.

Una expresión match debe ser completa. Si la expresión del sujeto no es manejada por ningún brazo match se lanza un UnhandledMatchError.

Ejemplo #2 Ejemplo de una expresión match no controlada

<?php
$condition 
5;

try {
    
match ($condition) {
        
1=> foo(),
        
3=> bar(),
    };
} catch (\
UnhandledMatchError $e) {
    
var_dump($e);
}
?>

El resultado del ejemplo sería:

object(UnhandledMatchError)#1 (7) {
  ["message":protected]=>
  string(33) "Unhandled match value of type int"
  ["string":"Error":private]=>
  string(0) ""
  ["code":protected]=>
  int(0)
  ["file":protected]=>
  string(9) "/in/ICgGK"
  ["line":protected]=>
  int(6)
  ["trace":"Error":private]=>
  array(0) {
  }
  ["previous":"Error":private]=>
  NULL
}

Usando expresiones match para manejar comprobaciones de no identidad

Es posible utilizar un expresión match para manejar casos de condicionales de no identidad usando true como expresión del sujeto.

Ejemplo #3 Uso de expresiones match generalizadas para ramificar en rangos de integers

<?php

$age 
23;

$result match (true) {
    
$age >= 65 => 'senior',
    
$age >= 25 => 'adult',
    
$age >= 18 => 'young adult',
    default => 
'kid',
};

var_dump($result);
?>

El resultado del ejemplo sería:

string(11) "young adult"

Ejemplo #4 Uso de expresiones match generalizadas para ramificar el contenido de strings.

<?php

$text 
'Bienvenue chez nous';

$result match (true) {
    
str_contains($text'Welcome') || str_contains($text'Hello') => 'en',
    
str_contains($text'Bienvenue') || str_contains($text'Bonjour') => 'fr',
    
// ...
};

var_dump($result);
?>

El resultado del ejemplo sería:

string(2) "fr"
add a note add a note

User Contributed Notes 7 notes

up
29
Hayley Watson
1 year ago
As well as being similar to a switch, match expressions can be thought of as enhanced lookup tables — for when a simple array lookup isn't enough without extra handling of edge cases, but a full switch statement would be overweight.

For a familiar example, the following
<?php

function days_in_month(string $month): int
{
    static
$lookup = [
   
'jan' => 31,
   
'feb' => 0,
   
'mar' => 31,
   
'apr' => 30,
   
'may' => 31,
   
'jun' => 30,
   
'jul' => 31,
   
'aug' => 31,
   
'sep' => 30,
   
'oct' => 31,
   
'nov' => 30,
   
'dec' => 31
   
];

   
$name = strtolower(substr($name, 0, 3));

    if(isset(
$lookup[$name])) {
        if(
$name == 'feb') {
            return
is_leap($year) ? 29 : 28;
        } else {
            return
$lookup[$name];
        }
    }
    throw new
InvalidArgumentException("Bogus month");
}

?>

with the fiddly stuff at the end, can be replaced by

<?php
function days_in_month(string $month): int
{
    return
match(strtolower(substr($name, 0, 3))) {
       
'jan' => 31,
       
'feb' => is_leap($year) ? 29 : 28,
       
'mar' => 31,
       
'apr' => 30,
       
'may' => 31,
       
'jun' => 30,
       
'jul' => 31,
       
'aug' => 31,
       
'sep' => 30,
       
'oct' => 31,
       
'nov' => 30,
       
'dec' => 31,
        default => throw new
InvalidArgumentException("Bogus month"),
    };
}
?>

Which also takes advantage of "throw" being handled as of PHP 8.0 as an expression instead of a statement.
up
14
darius dot restivan at gmail dot com
9 months ago
This will allow for a nicer FizzBuzz solution:

<?php

function fizzbuzz($num) {
    print
match (0) {
       
$num % 15 => "FizzBuzz" . PHP_EOL,
       
$num % => "Fizz" . PHP_EOL,
       
$num % => "Buzz" . PHP_EOL,
        default   =>
$num . PHP_EOL,
    };
}

for (
$i = 0; $i <=100; $i++)
{
   
fizzbuzz($i);
}
up
17
webmaster at warkensoft dot com
10 months ago
In the "familiar example" presented by Hayley Watson the following code is incorrect:

strtolower(substr($name, 0, 3))

It should instead be written in both instances as:

strtolower(substr($month, 0, 3))
up
8
lewiscowles at me dot com
10 months ago
The comment correcting Hayley's example misses that year is also present in the example, but not a function argument.

Most code from PHP.net should not be copied without user care. It was nonetheless, a great example of using short syntax to reduce complexity.
up
10
Anonymous
4 months ago
<?php
function days_in_month(string $month): int
{
    return
match(strtolower(substr($name, 0, 3))) {
       
'jan' => 31,
       
'feb' => is_leap($year) ? 29 : 28,
       
'mar' => 31,
       
'apr' => 30,
       
'may' => 31,
       
'jun' => 30,
       
'jul' => 31,
       
'aug' => 31,
       
'sep' => 30,
       
'oct' => 31,
       
'nov' => 30,
       
'dec' => 31,
        default => throw new
InvalidArgumentException("Bogus month"),
    };
}
?>

can be more concisely written as

<?php
function days_in_month(string $month): int
{
    return
match(strtolower(substr($name, 0, 3))) {
       
'apr', 'jun', 'sep''nov'  => 30,       
       
'jan', 'mar', 'may', 'jul', 'aug''oct', 'dec'  => 31,
       
'feb' => is_leap($year) ? 29 : 28,
        default => throw new
InvalidArgumentException("Bogus month"),
    };
}
?>
up
1
tm
2 months ago
If you are using a match expression for non-identity checks as described above make sure whatever you are using is actually returning `true` on success.

Quite often you rely on truthy vs. falsy when using if conditions and that will not work for match (for example `preg_match`). Casting to bool will solve this issue.
up
0
manoj904378 at gmail dot com
1 month ago
When & Where should you use?  that's most important part of match

<?php
    $Error_Code
=(int) 400;
   
$message=(string) match($Error_Code){
       
200=>"OK",
       
400=>"Bad Request",
       
401=>"Unauthorized",
       
403=>"Forbidden",
       
404=>"Not Found",
        default=>
"Unknown Error"
   
};
   
var_dump($message); // string(11) "Bad Request"
?>
To Top