PHP入門 繰り返し処理

PHPの繰り返し構文のwhile/do~while、for/foreach命令について解説しています。

while/do~while命令

while/do~while命令には、与えられた条件式がtrue(真)である間、ループを繰り返します。while命令はループの先頭で条件式を判定(前置判定)するのに対して、do~while命令はループの最後に判定(後置判定)しています。この違いは、「ループを開始する時点で条件式がfalseである場合」に、結果として現れてきます。後置判定では、条件式に関わらず必ず1回はループが実行されますが、前置判定では、条件次第では1回もループが実行されないことがあります。

構文:while命令

while(条件式){
  //条件式がtrueである間、繰り返し実行する処理
}
<?php
$i = 1;
while ($i < 6){
  print "{$i}番目のループです。<br />";
  $i++;
}
実行結果
実行結果

構文:do~while命令

do~while命令の末尾には、文の区切りを表すセミコロン(;)が必要です。

do{
  //条件式がtrueである間、繰り返し実行する処理
}while(条件式);
<?php
$i = 1;
do {
  print "{$i}番目のループです。<br />";
  $i++;
} while ($i < 6);
実行結果
実行結果

無限ループ

whileを使用して永久に終了しない無限ループにすることができます。次のソースコードで無限ループになります。ただ、無限ループはサーバーに負荷をかけ、OS自体フリーズする可能性があります。

<?php
$i = 1;
while ($i < 6){
  print "{$i}番目のループです。<br />";
}

for命令

for命令はあらかじめ指定された回数だけ処理を繰り返します。for命令では先頭の「初期化式」「継続条件式」「増減式」を使って、ループの継続条件/終了を管理します。

構文:for命令

for(初期化式; 継続条件式; 増減式){
  //ループ内で実行する処理
}
<?php
for($i = 1; $i < 6; $i++){
  print "{$i}番目のループです。<br />";
}

1、初期化式

初期化式は、forブロックに入った最初のループで一度だけ実行されます。一般的には、ここでカウンター変数(ループ変数)を初期化します。カウンター変数とはfor命令によるループの回数を管理する変数のことです。

カウンター変数には、慣例的にi、j、k・・・を利用します。この慣例は、古くはFORTRANの時代にまでさかのぼります。FORTRANでは「暗黙の型宣言」という仕組みがあり、i~nで始まる変数は整数型とみなされるという規則がありました。

2、継続条件式

継続条件式は、forループを継続するための条件を表します。ループを開始するたびに判定し、条件を満たさなくなったところで、forブロックを終了します。この例では、「$i < 6」なので、カウンター変数iが6未満(1~5)である間だけループを繰り返します。

3、増減式

ループ内の処理が1回終わるたびに実行されます。一般的に、カウンター変数を増減するためのインクリメント/デクリメント演算子、または、複合代入演算子で表します。ここでは、「$i++」としているので、ループのつど、カウンター変数iに1加算します。「$i+=2」とすればカウンター変数を2ずつ加算することもできます。「$i–」とすることで1ずつ減算するこも可能です。

for命令の注意点

1、無限ループはfor命令でも発生する

次のようなコードではforでも無限ループが発生します。カウンター変数$iの初期値が1で、その後は「$i–」で減算されていくだけなので、条件式は「$i < 6」がfalseになることはないからです。

for($i = 1; $i < 6; $i--){・・・}

継続条件式が省略されると、for命令は無条件にtrue(継続)とみなすためです。

for($i = 1; ; $i++){・・・}      //継続条件式を省略
for(; ;){・・・}                 //すべての式を省略

2、カウンター変数に浮動小数点型を利用しない

カウンター変数に浮動小数点型を利用するのは意味がないだけでなく、有害です。

3、ブロックは以下でカウンター変数を操作しない

次のようなコードは避けましょう。カウンター変数は増減式のみで更新する。

<?php
for($i = 1; $i < 6; $i++){
  if($i % 2 == 0){
    $i++;
  }
  print "{$i}<br />";
}

カンマ演算子

カンマ演算子(,)を利用することで、初期化式、継続条件式、増減式に複数の式を指定することもできます。カンマで区切られた式は先頭から順に実行されます。

この場合、print命令と加算子とが増減式としてループのたびに実行されます。ブロックがない場合は、「for(~);」のように末尾をセミコロン(;)で終了します。

<?php
for($i = 1; $i < 6; print "{$i}番目のループです。<br />" , $i++);

ここでは、初期化式でカウンター変数$iと$jを初期化し、継続条件式で両者の積を求め、さらに増減式では$iと$jの双方をインクリメントしています。

<?php
for($i = 1 , $j = 1; $result = $i * $j , $i < 6; $i++, $j++){
  print "{$i} × {$j}={$result}<br />";
}
実行結果
実行結果

foreach命令

foreach命令は、指定された配列/連想配列の要素を取り出して、先頭から順番に処理します。キー変数/値変数(まとめて仮変数とも言います)は、配列や連想配列から取り出した各要素のキー/値を一時的に格納する変数です。foreachのブロック内では、この仮変数を介して個々の要素にアクセスします。

構文:foreach命令(配列)

foreach(配列 as 値変数){
  //ループ内で実行する処理
}
<?php
$data = ['山田', '田中', '鈴木','井上','和田'];
foreach ($data as $value){
  print "名前は{$value}<br />";
}
実行結果
実行結果

構文:foreach命令(連想配列)

foreach(連想配列 as キー変数 => 値変数){
  //ループ内で実行する処理
}

「foreach($data as $key => $value)」の構文は、通常配列に対しても利用できます。その場合、仮変数$keyには配列のインデックス番号がセットされます。

<?php
$data = ['山田' => '男', '田中' => '女', 
         '鈴木' => '男','井上' => '男',
         '和田' => '女'];
foreach ($data as $key => $value){
  print "{$key}:{$value}<br />";
}
実行結果
実行結果

for命令による書き換え

foreach命令は、for命令で書き換えることもできます。countは配列のサイズを求めるための関数です。この例であれば0からcount($data)の範囲でカウンター変数を変化させることで、配列内のすべての要素を取得しています。

<?php
$data = ['山田', '田中', '鈴木','井上','和田'];
for ($i = 0; $i < count($data); $i++){
  print "名前は{$data[$i]}<br />";
}

値変数の参照渡し

foreachブロックの中で配列の要素を変更したいという場合には、値変数を参照渡しする必要があります。参照わたしとは、値を格納したメモリ上のアドレスをコピーする手法です。値変数の頭に「&」演算子を付与することで、配列の内容は値変数に参照渡しされるようになります。参照渡しされた先での変更は、もともとの変数にも反映されます。

foreachループでの仮変数の変更は、コードの見通しが悪くなる可能性があるので、配列可能する場合は、array_map関数を使用します。
<?php
$data = ['山田', '田中', '鈴木','井上','和田'];
foreach ($data as &$value){
  $value = 'New' . $value;
}
print_r($data);
実行結果
実行結果

foreach命令での分割代入

foreach命令と分割代入を組み合わせることで、入れ子の配列をループ内で分解することも可能です。

<?php
$books = [
  ['わかるPython',3500],
  ['わかるJava',2500],
  ['わかるC#',3000],
];
foreach($books as [$title, $price]){
  print "{$title} ({$price}円) <br />";
}
実行結果

同様に、連想配列の配列であれば次のようになります。

<?php
$books = [
  [ 'title' => 'わかるPython','price' => 3500],
  [ 'title' => 'わかるJava','price' => 2500],
  [ 'title' => 'わかるC#','price' => 3000],
];
foreach($books as [$title => $title, 'price' => $price]){
  print "{$title} ({$price}円) <br />";
}
実行結果
実行結果

配列への代入

分割代入では、配列形式の変数への代入も可能です。これを利用して、連想配列の配列から特定のキーを取り出して、新たな配列を生成することも可能です。➊の部分は、連想配列$bookからisbnキーのものを取り出し、配列$isbnの末尾($isbn[])に追加します。

<?php
$books = [
  [ 'isbn' => '978-4-7981-6333-1' , 'title' => 'わかるPython'],
  [ 'isbn' => '978-4-7981-6333-2' , 'title' => 'わかるJava'],
  [ 'isbn' => '978-4-7981-6333-2' , 'title' => 'わかるC#'],
];
foreach($books as $book){
  ['isbn' => $isbn[]]; = $book;  //➊
}
print_r($isbn);
実行結果
実行結果