PHP 8.4.2 Released!

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文は、行毎に実行されます。 (実際には、文毎に実行されます。)初めは、何も実行しません。 switch式の値と同じ値として評価される式を有する case文が見つけられたときに初めて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を付加することを避けたいと 思うかもしれませんが)、 break文を忘れないようにすることが重要です。

switch文では、条件は1度だけ評価され、 その結果が各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 にマッチしない場合に実行されます。例を以下に示します。

<?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 を置くと、 E_COMPILE_ERROR エラーが発生します。

注意: 技術的には、 default は switch 文の中のどの位置でも置くことができます。 default は他の 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文の値として指定するやり方が使えます。 もしくは、switch文ではなく、 if-elseブロックが使えます。

<?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;
}
// "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
'ツボルグ';
case
'カールスバーグ';
case
'ステラ';
case
'ハイネケン';
echo
'いいっすねぇ';
break;
default;
echo
'ほかのを選んでみませんか?';
break;
}
?>

参考

add a note

User Contributed Notes 6 notes

up
289
MaxTheDragon at home dot nl
12 years ago
This is listed in the documentation above, but it's a bit tucked away between the paragraphs. The difference between a series of if statements and the switch statement is that the expression you're comparing with, is evaluated only once in a switch statement. I think this fact needs a little bit more attention, so here's an example:

<?php
$a
= 0;

if(++
$a == 3) echo 3;
elseif(++
$a == 2) echo 2;
elseif(++
$a == 1) echo 1;
else echo
"No match!";

// Outputs: 2

$a = 0;

switch(++
$a) {
case
3: echo 3; break;
case
2: echo 2; break;
case
1: echo 1; break;
default: echo
"No match!"; break;
}

// Outputs: 1
?>

It is therefore perfectly safe to do:

<?php
switch(winNobelPrizeStartingFromBirth()) {
case
"peace": echo "You won the Nobel Peace Prize!"; break;
case
"physics": echo "You won the Nobel Prize in Physics!"; break;
case
"chemistry": echo "You won the Nobel Prize in Chemistry!"; break;
case
"medicine": echo "You won the Nobel Prize in Medicine!"; break;
case
"literature": echo "You won the Nobel Prize in Literature!"; break;
default: echo
"You bought a rusty iron medal from a shady guy who insists it's a Nobel Prize..."; break;
}
?>

without having to worry about the function being re-evaluated for every case. There's no need to preemptively save the result in a variable either.
up
121
septerrianin at mail dot ru
6 years ago
php 7.2.8.
The answer to the eternal question " what is faster?":
1 000 000 000 iterations.

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

Results:
if: 69sec
switch: 42sec
up
82
nospam at please dot com
24 years ago
Just a trick I have picked up:

If you need to evaluate several variables to find the first one with an actual value, TRUE for instance. You can do it this was.

There is probably a better way but it has worked out well for me.

switch (true) {

case (X != 1):

case (Y != 1):

default:
}
up
6
me at czarpino dot com
2 years ago
Although noted elsewhere, still worth noting is how loose comparison in switch-case was also affected by the change in string to number comparison. Prior PHP8, strings were converted to int before comparison. The reverse is now true which can cause issues for logic that relied on this behavior.

<?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"'
?>
up
1
php at nospam dot k39 dot se
4 months ago
It is possible to prevent nested switch/match/if blocks by checking for multiple cases at once (just beware that PHP uses loose comparison here).

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

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

If for some cases one of the values is not important, you can use the variable itself:

<?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
?>
up
4
j dot kane dot third at gmail dot com
2 years ago
The default case appears to always be evaluated last. If break is excluded from the default case, then the proceeding cases will be reevaluated. This behavior appears to be undocumented.

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