PHP 8.1.31 Released!

match

(PHP 8)

match (eşleşme) ifadesi, bir değerin özdeşlik denetimine dayalı olarak değerlendirmesini dallara ayırır. Switch deyimine benzer şekilde, bir match ifadesinin birden çok alternatifle karşılaştırılan bir özne ifadesi vardır. switch'in aksine, üçlü ifadeler gibi bir değere indirgeyecektir. switch aksine, karşılaştırma zayıf bir eşitlik denetiminden (==) ziyade bir özdeşlik denetimidir (===). Eşleşme ifadeleri PHP 8.0.0'dan itibaren mevcuttur.

Örnek 1 match ifadesinin yapısı

<?php
$dönüş değeri
= match (özne_ifade) {
tekil_koşullu_ifade => dönüş_ifadesi,
koşullu_ifade1, koşullu_ifade2 => dönüş_ifadesi,
};
?>

Örnek 2 match temel kullanım örneği

<?php
$yiyecek
= 'börek';

$dönen_değer = match ($yiyecek) {
'meyva' => 'Bu bir meyva',
'çorba' => 'Bu bir çorba',
'börek' => 'Bu bir börek',
};

var_dump($dönen_değer);
?>

Yukarıdaki örneğin çıktısı:

string(13) "Bu bir börek"

Örnek 3 Karşılaştırma işleçleriyle match kullanımı

<?php
$age
= 18;

$output = match (true) {
$age < 2 => "Bebek",
$age < 13 => "Çocuk",
$age <= 19 => "Genç",
$age > 19 => "Yetişkin",
$age >= 65 => "Yaşlı"
};

var_dump($output);
?>

Yukarıdaki örneğin çıktısı:

string(8) "Genç"

Bilginize: match ifadesinin sonucunun kullanılmasına gerek yoktur.

Bilginize: match ifadesi mutlaka bir noktalı virgül ; ile sonlandırılmalıdır.

match ifadesi switch deyimine benzemekle birlikte bazı önemli farklar vardır:

  • Bir match kolu, değeri birebir (===) değerlendirir, switch deyimin yaptığı gibi gevşekçe değil.
  • match ifadesi bir değer döndürür.
  • match kolları switch deyimlerini yaptığı gibi sonraki durumlarda başarısız olmaz.
  • match ifadesi kapsamlı olmalıdır.

switch deyimleri gibi, match ifadeleri de eşleşmeleri sırayla değerlendirir. Başlangıçta hiçbir kod çalıştırılmaz. Koşullu ifadeler yalnızca, tüm önceki koşullu ifadeler özne ifadeyle eşleşmede başarısız olmuşlarsa değerlendirilir. Yalnızca eşleşen koşullu ifadeye karşılık gelen dönüş ifadesi değerlendirilir. Örneğin:

<?php
$sonuç
= match ($x) {
foo() => ...,
$this->bar() => ..., // foo() === $x ise $this->bar çağrılmaz
$this->baz => beep(), // $x === $this->baz olmadıkça beep() çağrılmaz
// vb.
};
?>

match ifadesinin kolları virgüllerle ayrılmış çok sayıda ifade içerebilir. Bu bir mantıksal VEYA olup, aynı sağ taraflı çok sayıda eşleşme kolu için bir kısa yoldur.

<?php
$sonuç
= match ($x) {
// Bu eşleşme kolu:
$a, $b, $c => 5,
// Aşağıdaki üç eşleşme koluna eşdeğerdir:
$a => 5,
$b => 5,
$c => 5,
};
?>

Özel bir durum default kalıbıdır. Bu kalıp evvelce eşleşmemiş herşeyle eşleşir. Örnek:

<?php
$ifadeSonucu
= match ($koşul) {
1, 2 => foo(),
3, 4 => bar(),
default =>
baz(),
};
?>

Bilginize: Çok sayıda default kalıbı bir E_FATAL_ERROR hatasına (ölümcül hataya) yol açar.

match ifadesi kapsamlı olmalıdır. Konu ifadesi herhangi bir eşleşme kolu tarafından işlenmezse, bir UnhandledMatchError (başarısız eşleşme hatası) yavrulanır.

Örnek 4 - Başarısız eşleşme hatası örneği

<?php
$özne
= 5;

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

Yukarıdaki örneğin çıktısı:

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
}

- Başarısız eşleşmeleri işlemek için match ifadelerin kullanımı

Özne ifadesi olarak true kullanarak özdeş olmayan koşullu durumları ele almak için bir match ifadesi kullanmak mümkündür.

Örnek 5 - Tamsayı aralıklarında dallanmak için genelleştirilmiş eşleşme ifadelerinin kullanılması

<?php

$yaş
= 23;

$result = match (true) {
$yaş >= 65 => 'yaşlı',
$yaş >= 25 => 'yetişkin',
$yaş >= 18 => 'genç',
default =>
'çocuk',
};

var_dump($result);
?>

Yukarıdaki örneğin çıktısı:

string(11) "genç"

Örnek 6 - Dize içeriklerde dallanmak için genelleştirilmiş eşleşme ifadelerinin kullanılması

<?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);
?>

Yukarıdaki örneğin çıktısı:

string(2) "fr"
add a note

User Contributed Notes 9 notes

up
92
darius dot restivan at gmail dot com
3 years ago
This will allow for a nicer FizzBuzz solution:

<?php

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

for (
$i = 0; $i <=100; $i++)
{
fizzbuzz($i);
}
up
73
Anonymous
3 years ago
<?php
function days_in_month(string $month, $year): int
{
return match(
strtolower(substr($month, 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, $year): int
{
return match(
strtolower(substr($month, 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
54
Hayley Watson
3 years 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($month, 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
10
thomas at zuschneid dot de
1 year ago
While match allows chaining multiple conditions with ",", like:
<?php
$result
= match ($source) {
cond1, cond2 => val1,
default =>
val2
};
?>
it seems not valid to chain conditions with default, like:
<?php
$result
= match ($source) {
cond1 => val1,
cond2, default => val2
};
?>
up
6
Sbastien
1 year ago
I use match instead of storing PDOStatement::rowCount() result and chaining if/elseif conditions or use the ugly switch/break :

<?php

$sql
= <<<SQL
INSERT INTO ...
ON DUPLICATE KEY UPDATE ...
SQL;

$upkeep = $pdo->prepare($sql);

$count_untouched = 0;
$count_inserted = 0;
$count_updated = 0;

foreach (
$data as $record) {
$upkeep->execute($record);
match (
$upkeep->rowCount()) {
0 => $count_untouched++,
1 => $count_inserted++,
2 => $count_updated++,
};
}

echo
"Untouched rows : {$count_untouched}\r\n";
echo
"Inserted rows : {$count_inserted}\r\n";
echo
"Updated rows : {$count_updated}\r\n";
up
7
tolga dot ulas at tolgaulas dot com
8 months ago
Yes it currently does not support code blocks but this hack works:

match ($foo){
'bar'=>(function(){
echo "bar";
})(),
default => (function(){
echo "baz";
})()
};
up
13
php at joren dot dev
2 years ago
If you want to execute multiple return expressions when matching a conditional expression, you can do so by stating all return expressions inside an array.

<?php
$countries
= ['Belgium', 'Netherlands'];
$spoken_languages = [
'Dutch' => false,
'French' => false,
'German' => false,
'English' => false,
];

foreach (
$countries as $country) {
match(
$country) {
'Belgium' => [
$spoken_languages['Dutch'] = true,
$spoken_languages['French'] = true,
$spoken_languages['German'] = true,
],
'Netherlands' => $spoken_languages['Dutch'] = true,
'Germany' => $spoken_languages['German'] = true,
'United Kingdom' => $spoken_languages['English'] = true,
};
}

var_export($spoken_languages);
// array ( 'Dutch' => true, 'French' => true, 'German' => true, 'English' => false, )

?>
up
4
mark at manngo dot net
2 years ago
While you can’t polyfill a language construct, you can mimic the basic behaviour with a simple array.

Using example 2 above:

<?php
$food
= 'apple';
$return_value = match ($food) {
'apple' => 'This food is an apple',
'bar' => 'This food is a bar',
'cake' => 'This food is a cake',
};
print
$return_value;
?>

… you can get something similar with:

<?php
$food
= 'apple';
$return_value = [
'apple' => 'This food is an apple',
'bar' => 'This food is a bar',
'cake' => 'This food is a cake',
][
$food];
print
$return_value;
?>
up
1
tm
3 years 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.
To Top