PHP Conference Japan 2024

switch

(PHP 4, PHP 5, PHP 7, PHP 8)

switch 語句類似於對同一個表達式進行的一系列 IF 語句。在許多情況下,您可能希望將同一個變數(或表達式)與許多不同的值進行比較,並根據它等於哪個值執行不同的程式碼片段。這正是 switch 語句的用途。

注意請注意,與其他一些語言不同,continue 語句適用於 switch,並且行為類似於 break。如果您在迴圈內有 switch,並希望繼續到外部迴圈的下一次迭代,請使用 continue 2

注意:

請注意,switch/case 執行的是寬鬆比較

在以下範例中,每個程式碼區塊都是等效的。一個使用一系列 ifelseif 語句,另一個使用 switch 語句。在每種情況下,輸出都相同。

範例 #1 switch 結構

<?php
// 這個 switch 語句:

switch ($i) {
case
0:
echo
"i 等於 0";
break;
case
1:
echo
"i 等於 1";
break;
case
2:
echo
"i 等於 2";
break;
}

// 等同於:

if ($i == 0) {
echo
"i 等於 0";
} elseif (
$i == 1) {
echo
"i 等於 1";
} elseif (
$i == 2) {
echo
"i 等於 2";
}
?>

為了避免錯誤,理解 switch 語句的執行方式非常重要。switch 語句逐行執行(實際上是逐個語句執行)。一開始,不會執行任何程式碼。只有在找到一個 case 語句,其表達式求值結果與 switch 表達式的值相符時,PHP 才開始執行語句。PHP 會繼續執行語句,直到 switch 區塊的結尾,或第一次看到 break 語句。如果您在 case 的語句清單結尾沒有寫 break 語句,PHP 將繼續執行下一個 case 的語句。例如

<?php
switch ($i) {
case
0:
echo
"i 等於 0";
case
1:
echo
"i 等於 1";
case
2:
echo
"i 等於 2";
}
?>

這裡,如果 $i 等於 0,PHP 將執行所有的 echo 語句!如果 $i 等於 1,PHP 將執行最後兩個 echo 語句。只有在 $i 等於 2 時,您才會獲得預期的行為(將顯示「i 等於 2」)。因此,不要忘記 break 語句非常重要(即使您可能在某些情況下故意避免提供它們)。

switch 語句中,條件只會求值一次,然後將結果與每個 case 語句進行比較。在 elseif 語句中,條件會再次求值。如果您的條件比簡單比較更複雜,或是在緊密迴圈中,switch 可能會更快。

case 的語句清單也可以是空的,這只會將控制權傳遞到下一個 case 的語句清單。

<?php
switch ($i) {
case
0:
case
1:
case
2:
echo
"i 小於 3 但不是負數";
break;
case
3:
echo
"i 是 3";
}
?>

一個特殊的情況是 default case。這個 case 會比對其他 case 未比對到的任何內容。例如

<?php
switch ($i) {
case
0:
echo
"i 等於 0";
break;
case
1:
echo
"i 等於 1";
break;
case
2:
echo
"i 等於 2";
break;
default:
echo
"i 不等於 0、1 或 2";
}
?>

注意多個 default case 將會引發 E_COMPILE_ERROR 錯誤。

注意從技術上講,default case 可以按任何順序列出。只有在沒有其他 case 比對時才會使用它。但是,按照慣例,最好將它放在最後作為最後一個分支。

如果沒有 case 分支符合,並且沒有 default 分支,則不會執行任何程式碼,就像沒有 if 語句為 true 一樣。

case 值可以作為表達式給出。但是,該表達式將單獨求值,然後與 switch 值進行寬鬆比較。這表示它不能用於對 switch 值進行複雜的求值。例如

<?php
$target
= 1;
$start = 3;

switch (
$target) {
case
$start - 1:
print
"A";
break;
case
$start - 2:
print
"B";
break;
case
$start - 3:
print
"C";
break;
case
$start - 4:
print
"D";
break;
}

// 印出 "B"
?>

對於更複雜的比較,可以使用值 true 作為 switch 值。或者,也可以使用 if-else 區塊而不是 switch

<?php
$offset
= 1;
$start = 3;

switch (
true) {
case
$start - $offset === 1:
print
"A";
break;
case
$start - $offset === 2:
print
"B";
break;
case
$start - $offset === 3:
print
"C";
break;
case
$start - $offset === 4:
print
"D";
break;
}

// Prints "B"
?>

控制結構的替代語法也支援 `switch`。更多資訊請參閱控制結構的替代語法

<?php
switch ($i):
case
0:
echo
"i 等於 0";
break;
case
1:
echo
"i 等於 1";
break;
case
2:
echo
"i 等於 2";
break;
default:
echo
"i 不等於 0、1 或 2";
endswitch;
?>

在 `case` 後面可以使用分號而不是冒號,例如:

<?php
switch($beer)
{
case
'tuborg';
case
'carlsberg';
case
'stella';
case
'heineken';
echo
'好選擇';
break;
default;
echo
'請重新選擇...';
break;
}
?>

參見

新增註解

使用者貢獻的註解 6 則註解

289
MaxTheDragon at home dot nl
12 年前
這在上面的文件中列出,但它有點隱藏在段落之間。一連串 `if` 語句和 `switch` 語句之間的區別在於,您要比較的表達式在 `switch` 語句中只會求值一次。我認為這個事實需要多加注意,所以這裡有一個範例:

<?php
$a
= 0;

if(++
$a == 3) echo 3;
elseif(++
$a == 2) echo 2;
elseif(++
$a == 1) echo 1;
else echo
"沒有匹配!";

// 輸出:2

$a = 0;

switch(++
$a) {
case
3: echo 3; break;
case
2: echo 2; break;
case
1: echo 1; break;
default: echo
"沒有匹配!"; break;
}

// 輸出:1
?>

因此,執行以下操作是完全安全的:

<?php
switch(winNobelPrizeStartingFromBirth()) {
case
"和平": echo "您贏得諾貝爾和平獎!"; break;
case
"物理": echo "您贏得諾貝爾物理獎!"; break;
case
"化學": echo "您贏得諾貝爾化學獎!"; break;
case
"醫學": echo "您贏得諾貝爾醫學獎!"; break;
case
"文學": echo "您贏得諾貝爾文學獎!"; break;
default: echo
"您從一個可疑的傢伙那裡買了一塊生鏽的鐵製獎牌,他堅持說這是諾貝爾獎..."; break;
}
?>

而不必擔心該函數會針對每個 `case` 重新求值。也沒有必要預先將結果儲存在變數中。
121
septerrianin at mail dot ru
6 年前
php 7.2.8。
永恆問題「哪個更快?」的答案
1,000,000,000 次迭代。

<?php
$s
= time();
for (
$i = 0; $i < 1000000000; ++$i) {
$x = $i%10;
if (
$x == 1) {
$y = $x * 1;
} elseif (
$x == 2) {
$y = $x * 2;
} elseif (
$x == 3) {
$y = $x * 3;
} elseif (
$x == 4) {
$y = $x * 4;
} elseif (
$x == 5) {
$y = $x * 5;
} elseif (
$x == 6) {
$y = $x * 6;
} elseif (
$x == 7) {
$y = $x * 7;
} elseif (
$x == 8) {
$y = $x * 8;
} elseif (
$x == 9) {
$y = $x * 9;
} else {
$y = $x * 10;
}
}
print(
"if: ".(time() - $s)."sec\n");

$s = time();
for (
$i = 0; $i < 1000000000; ++$i) {
$x = $i%10;
switch (
$x) {
case
1:
$y = $x * 1;
break;
case
2:
$y = $x * 2;
break;
case
3:
$y = $x * 3;
break;
case
4:
$y = $x * 4;
break;
case
5:
$y = $x * 5;
break;
case
6:
$y = $x * 6;
break;
case
7:
$y = $x * 7;
break;
case
8:
$y = $x * 8;
break;
case
9:
$y = $x * 9;
break;
default:
$y = $x * 10;
}
}
print(
"switch: ".(time() - $s)."sec\n");
?>

結果
if: 69秒
switch: 42秒
82
nospam at please dot com
24 年前
這是我學到的一個小技巧

如果你需要評估數個變數,找出第一個具有實際值(例如 TRUE)的變數,你可以這樣做。

可能會有更好的方法,但這個方法對我來說效果不錯。

switch (true) {

case (X != 1)

case (Y != 1)

default
}
6
me at czarpino dot com
2 年前
雖然在其他地方也有提到,但仍然值得注意的是,switch-case 中的寬鬆比較也受到字串轉換為數字比較方式變更的影響。在 PHP8 之前,字串會先轉換為整數再進行比較。現在則相反,這可能會導致依賴此行為的邏輯出現問題。

<?php
function testSwitch($key) {
switch (
$key) {
case
'non numeric string':
echo
$key . ' matches "non numeric string"';
break;
}
}

testSwitch(0); // pre-PHP8, returns '0 matches "non numeric string"'
?>
1
php at nospam dot k39 dot se
4 個月前
可以透過一次檢查多個 case 來避免巢狀的 switch/match/if 區塊(請注意 PHP 在這裡使用寬鬆比較)。

<?php
$a
= "abc";
$b = "def";

switch ([
$a, $b]) {
case [
"abc", "def"]:
$result = 1;
break;
default:
$result = -1;
}
// $result == 1
?>

如果某些 case 中,其中一個值並不重要,你可以使用變數本身

<?php
$a
= "abc";
$b = "def";

switch ([
$a, $b]) {
case [
"xyz", "def"]:
$result = 1;
break;
case [
$a, "def"]:
$result = 2;
break;
default:
$result = -1;
}
// $result == 2
?>
4
j dot kane dot third at gmail dot com
2 年前
default case 看起來總是最後才被評估。如果 default case 中不包含 break,則會重新評估後續的 case。這個行為似乎沒有文件記載。

<?php

$kinds
= ['moo', 'kind1', 'kind2'];

foreach (
$kinds as $kind) {
switch(
$kind)
{
default:
// The kind wasn't valid, set it to the default
$kind = 'kind1';
var_dump('default');

case
'kind1':
var_dump('1');
break;

case
'kind2':
var_dump('2');
break;

case
'kindn':
var_dump('n-th');
break;
}

echo
"\n\n";
}

?>
To Top