PHPの制御構文

PHPのプログラムの実行は、基本的に上から下へ順次実行されますが、必要に応じて条件分岐処理や反復処理といった様々な制御構造を使用することができます。

if elseif else

if elseif else文は、条件として与えられた式を論理値として評価し、その結果によって処理を分岐します。下記の例では、式1がtrueであれば、文1を実行して処理を終了します。式1がfalseで式2がtrueであれば、文2を実行して処理を終了します。式1と式2がどちらもfalseであれば、文3を実行して処理を終了します。elseifとelseは、必要なければ省略可能です。また、elseifは必要に応じて、いくつでも記述できます。

PHP

<?php
if (式1) {
  文1
} elseif (式2) {
  文2
} else {
  文3
}
?>

PHPのif文は、コロン":"と"endif;"を用いて、下記のように記述することもできます。if文の途中でPHPブロックを抜ける場合などは、このように記述した方がわかりやすい場合があるので、適宜使い分けると良いでしょう。

PHP

<?php
$foo = 1;
$hoge = 0;
?>
<?php if ($foo < $hoge) : ?>
<p>$fooは、$hogeより小さいです。</p>
<?php elseif ($foo > $hoge) : ?>
<p>$fooは、$hogeより大きいです。</p>
<?php else : ?>
<p>$fooと$hogeは、同じです。</p>
<?php endif; ?>

while

while文は、条件として与えられた式を論理値として評価し、その結果がtrueの間、処理を反復します。下記の例では、まず式1を評価した結果がtrueであれば、文1を実行します。文1の処理が終わったら再び式1を評価し、式1がtrueである限り処理を繰り返し、式1がfalseになった時点で処理を終了します。もし、式1が最初からfalseであった場合は、文1は1度も実行されずに処理を終了します。

PHP

<?php
while (式1) {
  文1
}
?>

PHPのwhile文は、コロン":"と"endwhile;"を用いて、下記のように記述することもできます。while文は、条件式が常にtrueを返すようにしてしまうと無限ループ(処理が永遠に終わらない)になるので注意が必要です。

PHP

<?php
$foo = 0;
?>
<ul>
<?php while ($foo < 5) : ?>
<li>
<?php
$foo++;
echo 'hoge' . $foo;
?>
</li>
<?php endwhile; ?>
</ul>

do while

do while文は、while文とよく似ています。下記の例では、まず文1を実行します。次に式1を論理値として評価し、結果がtrueであれば再び文1を実行し、処理を繰り返します。そして、式1がfalseになった時点で処理を終了します。while文との違いは、式1が最初からfalseであっても、文1が1度は実行される点です。

PHP

<?php
do {
  文1
} while (式1);
?>

for

for文は、while文と同じように反復処理を行いますが、構文に変数の初期化、条件式、反復ごとに実行する式を含めることができます。これは好みにもよりますが、予め反復回数が決まっている処理に用いられることが多いです。

下記の例では、まず式1が実行されます。通常は、この式1で変数の初期化処理を行います。次に式2を評価した結果がtrueであれば文1を実行し、falseであれば処理を終了します。通常、式2は条件式となります。文1を実行した後、式3を実行します。通常、式3では式2の条件式で使用する変数の値を変更する処理を行います。次に再び式2を評価し、trueであれば文1の処理を繰り返し、falseであれば処理を終了します。

PHP

<?php
for (式1; 式2; 式3) {
  文1
}
?>

PHPのfor文は、コロン":"と"endfor;"を用いて、下記のように記述することもできます。下記の例では、最初に$fooを1で初期化し、$fooが5以下であれば反復処理をします。各反復処理の後、$fooに加算子で1を加えた上で、再び反復条件の判定をします。

PHP

<ul>
<?php for ($foo = 1; $foo <= 5; $foo++) : ?>
<li>hoge<?php echo $foo; ?></li>
<?php endfor; ?>
</ul>

foreach

foreach文は、配列に対して反復処理を行う構文です。配列に格納された各要素に対して処理を行いたいときに使用します。配列だけでなく、Iteratorインターフェイスを実装したオブジェクトも反復処理することができます。

下記の例では、配列の要素が$変数名に格納され、文1が実行されます。これを配列の要素の数だけ繰り返し実行します。通常、文1では$変数名に対して、何らかの処理を行います。

PHP

<?php
foreach (配列 as $変数名) {
  文1
}
?>

PHPのforeach文は、コロン":"と"endforeach;"を用いて、下記のように記述することもできます。下記の例では、foreachのループ処理で配列$fooの要素を$valueに取得し、その値をechoにより出力しています。

PHP

<ul>
<?php
$foo = array(1, 2, 3);
?>
<?php foreach ($foo as $value) : ?>
<li>
<?php echo $value; ?>
</li>
<?php endforeach; ?>
</ul>

PHPでは、下記のように記述することで、foreachによる配列の反復処理時にキーを取得することもできます。下記の例では、連想配列$hogeをforeachで反復処理する際に$keyにキーを取得し、echoでの出力に使用しています。

気を付けたいのは、PHPではブロックスコープがないため、foreachの処理を抜けた後でも、$keyと$valueには値が残る点です。試しにforeachの後で、$keyと$valueを出力してみると値が残っていることが確認できます。必要に応じて、unset()するようにしましょう。

PHP

<?php
$hoge = array(
  'a' => 1,
  'b' => 2,
  'c' => 3,
);
foreach ($hoge as $key => $value) {
  echo '$hoge[' . $key . '] : ' . $value . '<br />', PHP_EOL;
}
var_dump($key); // 出力:string(1) "c"
var_dump($value); // 出力:int(3)
unset($key);
unset($value);
var_dump(isset($key)); // 出力:bool(false)
var_dump(isset($value)); // 出力:bool(false)
?>

通常、foreachで配列の要素を変数に取得する際には、要素の値がコピーされていますが、変数名の先頭に&を付けることにより、参照を取得することができます。これにより、もとの配列の要素を変更することができます。

下記の例では、2つの配列の要素にforeachの処理で10を足しています。要素を取得する変数名に&を付けていない配列$barの要素は変更されていないのに対して、&を付けた配列$bazの要素は、値が変更されていることが確認できます。

foreachの処理で参照を取得した場合、foreachの処理を終えた後にも変数が参照を保持している点には、注意が必要です。下記では、foreachの処理後に$valueに対して別の値を代入していますが、$bazの要素まで書き換えられていることが確認できます。これは思わぬバグにつながりかねないので、必ずunset()することを心掛けましょう。

PHP

<?php
$bar = array(1, 2);
foreach ($bar as $value) {
  $value += 10;
}
var_dump($bar); // 出力:array(2) { [0]=> int(1) [1]=> int(2) }

$baz = array(1, 2);
foreach ($baz as &$value) {
  $value += 10;
}
var_dump($baz); // 出力:array(2) { [0]=> int(11) [1]=> &int(12) }
$value = '書き換えられました。';
var_dump($baz); // 出力:array(2) { [0]=> int(11) [1]=> &string(30) "書き換えられました。" }
unset($value);
var_dump($baz); // 出力:array(2) { [0]=> int(11) [1]=> string(30) "書き換えられました。" }
?>

switch

switch文は、条件分岐処理を行います。一つの式の値が何であるかによって、処理を分岐したい場合によく用いられます。下記の例では、まず式1の値を評価し、上から順番にcaseの値1〜値Nに等しい値を探します。もし等しい値があれば、それに続く文を実行し、次のbreak文でswitchの処理を終了します。等しい値がない場合は、defaultの文4を実行し、break文で処理を終了します。

PHP

<?php
switch (式1) {
  case 値1 :
    文1
    break;
  case 値2 :
    文2
    break;
  case 値N :
    文3
    break;
  default :
    文4
    break;
}
?>

PHPのswitch文は、コロン":"と"endswitch;"を用いて、下記のように記述することもできます。また、defaultの処理が必要なければ、省略可能です。下記の例では、defaultを省略しているため、$fooが2であった場合は、何も処理を行わずにswitch文を終了します。

PHP

<?php
$foo = 1;
switch ($foo) :
  case 0 :
    echo '$fooは、0です。', PHP_EOL;
    break;
  case 1 :
    echo '$fooは、1です。', PHP_EOL;
    break;
endswitch;
/* 出力:
$fooは、1です。
*/
?>

また、各caseにおいてbreak文を省略することもできます。この場合、次にbreak文がくるまでの処理を実行します。switch文で気を付けたいのは、値の比較が===による厳密な比較ではない点です。下記の例では、整数と文字列を比較していますが、自動的にキャストされて処理されていることがわかります。

PHP

<?php
$hoge = 1;
while ($hoge < 5) {
  switch ($hoge) {
    case '1' :
    case '3' :
      echo $hoge . 'は、奇数です。<br />', PHP_EOL;
      break;
    case '2' :
    case '4' :
      echo $hoge . 'は、偶数です。<br />', PHP_EOL;
      break;
  }
  $hoge++;
}
/* 出力:
1は、奇数です。<br />
2は、偶数です。<br />
3は、奇数です。<br />
4は、偶数です。<br />
*/
?>

break

break文は、実行中のwhile, do while, for, foreach, switchの処理を抜けるために使用します。下記の例では、for文で$iが10以下であれば処理を繰り返すようにしていますが、for文の中の処理で$iが5であれば、break文で処理を抜けるようにしています。結果、5までしか出力されないことが確認できます。

PHP

<?php
for ($i = 1; $i <= 10; $i++) {
  echo $i, PHP_EOL;
  if ($i === 5) {
    break;
  }
}
/* 出力:
1
2
3
4
5
*/
?>

PHPでは、break文のオプションで、ネストした構造を抜ける階層を指定することができます。下記の例では、break 1とした場合は内側のswitch文だけを抜け、break 2とした場合は外側のwhile文も抜けていることが確認できます。

PHP

<?php
$foo = 0;
while (++$foo) {
  echo $foo . '回目:';
  switch ($foo) {
    case 3 :
      echo '外側のwhile文を抜けて、ループ処理を終了します。<br />', PHP_EOL;
      break 2;
    default :
      echo '内側のswitch文を抜けて、ループ処理を続けます。<br />', PHP_EOL;
      break 1;
  }
}
/* 出力:
1回目:内側のswitch文を抜けて、ループ処理を続けます。<br />
2回目:内側のswitch文を抜けて、ループ処理を続けます。<br />
3回目:外側のwhile文を抜けて、ループ処理を終了します。<br />
*/
?>

continue

continue文は、反復構造の処理の中で残りの処理をスキップし、次の反復処理へ進むための構文です。下記の例では、$fooが奇数の場合には処理をスキップし、偶数の場合だけechoで出力するようにしています。

PHP

<?php
for ($foo = 1; $foo <= 10; $foo++) {
  if ($foo % 2 !== 0) {
    continue;
  }
  echo $foo, PHP_EOL;
}
/* 出力:
2
4
6
8
10
*/
?>

PHPでは、ネストした反復構造において、continue文のオプションでスキップする階層を指定することができます。その際、PHPではswitch文も反復構造と扱われる点には、注意が必要です。下記の例では、whileブロック内のswitch文で、$hogeが偶数の際にcontinue 2とすることでwhile文の処理をスキップしています。

PHP

<?php
$hoge = 0;
while (++$hoge < 10) {
  switch ($hoge) {
    case 2 :
    case 4 :
    case 6 :
    case 8 :
      continue 2;
  }
  echo $hoge, PHP_EOL;
}
/* 出力:
1
3
5
7
9
*/
?>

include / include_once

include文は、別のPHPファイルを読み込むための構文です。まず、下記のPHPスクリプトを記述したファイルをfoo.phpというファイル名で、実行するphpファイルと同階層に置いておきます。

PHP

<?php
// foo.php
echo 'foo.php', PHP_EOL;
class Foo
{
}

次に、include文でfoo.phpを読み込んでみます。foo.phpに記述されたechoは、includeで読み込まれた時点で出力されます。下記の例では、foo.phpに定義されたFooクラスのインスタンスを作成していますが、問題なく作成できていることが確認できます。

PHP

<?php
include 'foo.php';
$foo = new Foo();
var_dump($foo);
/* 出力:
foo.php
object(Foo)#1 (0) {
}
*/
?>

include_once文は、include文と同じように別のPHPファイルを読み込みますが、includeが同じファイルを複数回読み込めるのに対して、include_onceは同じファイルは1度しか読み込みません。PHPでは、同じ名前のクラスや関数を2度定義すると、Fatal errorが発生し実行が中止してしまいますが、include_onceを使うことで、これを防ぐことができます。

下記の例では、include_onceで同じファイルを2度読み込むようにしていますが、結果は1度しか読み込まれていないことがわかります。下記コードのinclude_onceをincludeに変更するとFatal errorが発生します。

PHP

<?php
include_once 'foo.php';
include_once 'foo.php';
$foo = new Foo();
var_dump($foo);
/* 出力:
foo.php
object(Foo)#1 (0) {
}
*/
?>

また、includeやinclude_onceで存在しないファイルを指定した場合は、E_WARNINGレベルの警告が発生した上で、処理は継続されます。下記の例では、includeで存在しないhoge.phpを読み込むようにしていますが、Warningが発生します。

PHP

<?php
include 'hoge.php'; // 出力:Warning発生
?>

require / require_once

require文は、include文と同じく、別のPHPファイルを読み込むための構文です。基本的にinclude文と同じですが、指定したファイルが存在しない場合に、includeはE_WARNINGの警告が発生した上で処理を継続するのに対して、requireやrequire_onceではFatal errorとなり、その時点で処理を停止する点に違いがあります。

PHP

<?php
require 'hoge.php'; // 出力:Fatal error発生
?>

また、includeの場合と同じように、requireは同じファイルを複数回読み込めるのに対して、require_onceは同じファイルは1度しか読み込みません。

return

return文は、記述された場所によって少し動作が異なります。もっとも多く使用されるのは、関数やメソッドの処理を中止し、呼び出し元に値を返す処理です。下記の例では、定義した2つの関数内でreturnを記述していますが、それぞれ値が返された上でreturn以降の処理は行われていないことが確認できます。また、戻り値(返り値)を省略した場合、値はNULLとなります。

PHP

<?php
function foo() {
  return 'foo';
  echo 'return以降の処理は行われません。', PHP_EOL;
}
function hoge() {
  return;
  echo 'return以降の処理は行われません。', PHP_EOL;
}
$foo = foo();
var_dump($foo);
$hoge = hoge();
var_dump($hoge);
/* 出力:
string(3) "foo"
NULL
*/
?>

グローバルスコープでreturnを記述した場合は、その時点で処理が終了します。下記の例では、HTMLを出力していますが、return以降はPHPブロックの外側の</body>や</html>も出力されていないことが確認できます。

PHP

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<?php
return;
/* 出力:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
*/
?>
</body>
</html>

requireやincludeで読み込まれたファイルでreturnを記述した場合は、その時点でそのファイルの処理を中止し、読み込み元のファイルに戻った上で処理を継続します。まず、下記のPHPスクリプトを記述したファイルをbar.phpというファイル名で、実行するphpファイルと同階層に置いておきます。

PHP

<?php
// bar.php
echo 'bar.php', PHP_EOL;
return 1;
echo 'return以降の処理は行われません。', PHP_EOL;

続いて、下記のようにrequireでbar.phpを読み込んでみます。すると、bar.phpのreturn以降の処理は中止されていますが、読み込み元の実行は継続されていることがわかります。また、bar.phpのreturnで返した値が、requireの戻り値として扱われていることが確認できます。

PHP

<?php
$bar = require 'bar.php';
var_dump($bar);
/* 出力:
bar.php
int(1)
*/
?>