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);
}match
Почист и полокален преглед на PHP референцата, со задржана структура од PHP.net и подобра читливост за примери, секции и белешки.
match
Референца за `control-structures.match.php` со подобрена типографија и навигација.
match
(PHP 8)
На match изразот гранки за евалуација врз основа на проверка на идентитет на вредност. Слично на switch изјава, еден
match израз има субјект израз што се споредува со повеќе алтернативи. За разлика од switch, тој ќе се евалуира до вредност многу како тернарни изрази. За разлика од switch, споредбата е проверка на идентитет (===) наместо слаба проверка на еднаквост (==). Изразите за совпаѓање се достапни од PHP 8.0.0.
Пример #1 Структура на match expression
<?php
$return_value = match (subject_expression) {
single_conditional_expression => return_expression,
conditional_expression1, conditional_expression2 => return_expression,
};
?>Пример #2 Основен match usage
<?php
$food = 'cake';
$return_value = match ($food) {
'apple' => 'This food is an apple',
'bar' => 'This food is a bar',
'cake' => 'This food is a cake',
};
var_dump($return_value);
?>Пример #1 Пример што покажува затворачка ознака што го опфаќа последниот нов ред
string(19) "This food is a cake"
Пример #3 Пример за користење match со оператори за споредба
<?php
$age = 18;
$output = match (true) {
$age < 2 => "Baby",
$age < 13 => "Child",
$age <= 19 => "Teenager",
$age >= 40 => "Old adult",
$age > 19 => "Young adult",
};
var_dump($output);
?>Пример #1 Пример што покажува затворачка ознака што го опфаќа последниот нов ред
string(8) "Teenager"
Забелешка: Резултатот од
matchизразот не мора да се користи.
Забелешка: Кога е
matchизразот се користи како самостоен израз, тој must мора да заврши со точка и запирка;.
На match изразот е сличен на
switch изјава, но има некои клучни разлики:
-
А
matchраката ги споредува вредностите строго (===) наместо лабаво како што прави изјавата switch. -
А
matchизразот враќа вредност. -
matchкраците не поминуваат до подоцнежните случаи на начинот на којswitchизјавите го прават тоа. -
А
matchизразот мора да биде исцрпен.
за листа на сите овие функции и соодветните switch изјави, match
изразите се извршуваат од рака до рака. На почетокот, не се извршува никаков код. Условните изрази се проценуваат само ако сите претходни условни изрази не успеале да се совпаднат со изразот на субјектот. Само изразот за враќање што одговара на условниот израз што се совпаѓа ќе биде проценет. На пример:
<?php
$result = match ($x) {
foo() => 'value',
$this->bar() => 'value', // $this->bar() isn't called if foo() === $x
$this->baz => beep(), // beep() isn't called unless $x === $this->baz
// etc.
};
?>
match краците на изразот може да содржат повеќе изрази разделени со запирка. Тоа е логичко ИЛИ, и е кратенка за повеќе краци за совпаѓање со истата страна од десната страна.
<?php
$result = match ($x) {
// This match arm:
$a, $b, $c => 5,
// Is equivalent to these three match arms:
$a => 5,
$b => 5,
$c => 5,
};
?>
Посебен случај е default образец. Овој образец совпаѓа со сè што не било претходно совпаднато. На пример:
<?php
$expressionResult = match ($condition) {
1, 2 => foo(),
3, 4 => bar(),
default => baz(),
};
?>Забелешка: Повеќе стандардни обрасци ќе предизвикаат
E_FATAL_ERRORerror.
А match изразот мора да биде исцрпен. Ако изразот на субјектот не е обработен од ниту еден крак за совпаѓање, а
UnhandledMatchError се фрла.
Пример #4 Пример за нетретиран израз за совпаѓање
<?php
$condition = 5;
try {
match ($condition) {
1, 2 => foo(),
3, 4 => bar(),
};
} catch (\UnhandledMatchError $e) {
var_dump($e);
}
?>Пример #1 Пример што покажува затворачка ознака што го опфаќа последниот нов ред
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
}
Користење изрази за совпаѓање за обработка на проверки што не се идентитет
Можно е да се користи match израз за обработка на условни случаи што не се идентитет со користење true како израз на субјектот.
Пример #5 Користење генерализирани изрази за совпаѓање за разгранување на опсези на цели броеви
<?php
$age = 23;
$result = match (true) {
$age >= 65 => 'senior',
$age >= 25 => 'adult',
$age >= 18 => 'young adult',
default => 'kid',
};
var_dump($result);
?>Пример #1 Пример што покажува затворачка ознака што го опфаќа последниот нов ред
string(11) "young adult"
Пример #6 Користење генерализирани изрази за совпаѓање за разгранување на содржина на стринг
<?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);
?>Пример #1 Пример што покажува затворачка ознака што го опфаќа последниот нов ред
string(2) "fr"
Белешки од корисници 10 белешки
<?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"),
};
}
?>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.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
};
?>Yes it currently does not support code blocks but this hack works:
match ($foo){
'bar'=>(function(){
echo "bar";
})(),
default => (function(){
echo "baz";
})()
};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, )
?>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";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;
?>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.Since `match` is a better alternative in MOST cases for modern software, adding this comment so that if someone googles "`switch` in PHP" then this page also shows in the search results.