【PHP】foreach文の使い方!

どーも!

たかぽんです!

今回はPHPでのforeach文の使い方をしっかりと確認しておこうと思います!

調べればちゃんとわかるんですが、なかなかどうして...

他の言語のforeachとか書いてPHPにもどってくると、細かいところであれ?ってなりがちなんですよね...w

ではみていきます!

foreach文の使い方!

まずは基本的なforeach文の使い方をみていきましょう!

基本的には配列の中の値を一つづつ取得してくる時によく用いられます。

ただ、そんな中でも連想配列になったり、indexを取得したり...色々ありますので、例と一緒に確認してみます!

配列から値を一件づつ取得

$articleList = ['article1', 'article2', 'article3', 'article4'];

foreach($articleList as $article) {
    echo($article . "\n");
}


// 以下出力結果
article1
article2
article3
article4

配列の中身から一件づつ表示します。

例えばですが、記事タイトルの一覧...といった配列があった場合、一件づつ処理をしたいとします。

その場合、このforeachを使って、$articleList as $article...といった形で一件づつ取り出し、処理が可能なわけです。

一般的に、asの左側にくるものは複数系だったり、複数のものを意味する言葉の変数になります。(Articlesや、ArticleList等...)

そして、その複数の変数を単数系に戻したもの、もしくはリストの一件のデータを表す言葉がasの右側にきます。

今回で言うと、$articleListの一件のデータとして、$articleを取り出します!

といった具合です。

例えばユーザーだったら...

"$users as $user" (たくさんのユーザーの中から一人づつユーザーを取り出す)といった命名になるイメージです。

連想配列から一件づつ値を取得

さて、通常の配列はわかりましたが、場合によっては連想配列(['hoge'=>'huga'])の場合にキーも取得したい場合があります。

そんな場合も同じくできるので、そちらの例をみてみます!

$articleList = [
    'article1' => 'content1', 
    'article2' => 'content2', 
    'article3' => 'content3', 
    'article4' => 'content4'
];

foreach($articleList as $article => $title) {
    echo($article . "のタイトル : " . "$title" . "\n");
}

// 以下出力結果
article1のタイトル : content1
article2のタイトル : content2
article3のタイトル : content3
article4のタイトル : content4

前述した例を理解した人ならサクッと理解できるかと思います。

asの中身として、 "key => value"の形で指定してあげると、以降その変数として扱うことが可能です。

先程はvalueしかなかったのですが、指定をすればkey, valueも取得できるわけですね!

また、このasに指定している "$article => $title"は変数なので、皆さんの自由に名前をつけて大丈夫です。

前述した通り、as手前の複数系に合わせて名前をつけ、特徴がわかりやすい名前をつけるといいかと思います。

index(現在の処理位置)を取得する

次に、foreachで配列を扱っていると、現在何番目の処理を行なっているのか?その情報(index)を合わせて取得することを考えます。

外部で適当な変数を用意して、インクリメント...なんて事せずとも取得ができるので、みていきましょう!

$articleList = ['article1', 'article2', 'article3', 'article4'];

foreach($articleList as $index => $article) {
    echo($index . ':' . $article . "\n");
}

// 以下出力結果
0:article1
1:article2
2:article3
3:article4

このような感じで0始まりで処理番号を取得できました!

1始まりにするためには$indexに対して1足してあげれば大丈夫です。

$articleList = ['article1', 'article2', 'article3', 'article4'];

foreach($articleList as $index => $article) {
    $beginFromOneIndex = $index+1;  // ここでindexに1を足す
    echo($beginFromOneIndex . ':' . $article . "\n");
}

// 以下出力結果
1:article1
2:article2
3:article3
4:article4

いい感じですね!

breakで途中で処理を止める

さて、今度はbreakについてです。

foreachは基本的には元の配列の要素数だけ繰り返されるのですが、途中で処理を止めたい場合もあると思います。

そんな場合はbreak文を使ってみましょう!

$articleList = ['article1', 'article2', 'article3', 'article4'];
foreach($articleList as $index => $article) {
    if($index === 2) { // indexが0,1の処理が行われた後、2でbreakする
        break;
    }
    echo($article . "\n");
}


// 以下出力結果
article1
article2

今回は先程のindexを用いて特定回数で止めるものを書いてみました。

indexは0始まりのため、それを考慮して止める際の条件($index === 2)の数値を考える必要があります。

もし前述した1始まりに変えた場合、2回処理を回すのであれば3になりますね。(if文の前に加算をした場合)

もちろん、index以外にもキーやバリューの値を用いて止めることも可能です。

状況に応じて切り替えましょう!

途中の処理を飛ばして次の処理を行いたい

foreachの処理を行なっていると、特定の値に対してはその処理を行いたいけど、他のものには処理をしたくない...!

というケースが出てきます。

そんな場合は条件で括るか、continueを使いましょう!

試しに、偶数番目の記事だけ表示する場合を考えてみます。(article2, article4)

条件で括る場合

$articleList = ['article1', 'article2', 'article3', 'article4'];
foreach($articleList as $index => $article) {
    if($index % 2 === 1) { // 表示したい場合のみ処理をする
        echo($article . "\n");
    }
}

continueを使った場合

$articleList = ['article1', 'article2', 'article3', 'article4'];
foreach($articleList as $index => $article) {
    if($index % 2 === 0) { // 表示したくない場合は次のループへ
        continue;
    }
    echo($article . "\n");
}

どちらも出力結果は同じなのですが、後者は早期リターン(今回はreturnではなくcontinueですが...)といわれていて、ネスト(for, if, foreachなどの入れ子)の深さが浅くなるため、おすすめです。

たとえば、行いたい処理がif分を含んでいた場合どちらが複雑になるかは明白ですね!

// 条件で処理を括る場合
foreach($articleList as $index => $article) {
    if($index % 2 === 1) { // 表示したい場合のみ処理をする
        if($hoge) {
            echo($article . "\n");
        }
    }
}

// 早期リターンの場合
foreach($articleList as $index => $article) {
    if($index % 2 === 0) { // 表示したくない場合は次のループへ
        continue;
    }
    if($hoge) {
        echo($article . "\n");
    }
}

echoに対してif分を一つ追加しましたが、インデントがより浅いことがわかるかと思います。

考える側としても、前者だといつくるかわからないブロックの中身がこの条件なんだな...?ってずっと頭の片隅に考える必要があります。

後者だと、早めにその条件に見切りをつけるので、以降の処理は全てその条件をみたしてるものに対する処理なんだと決めつけられますよね!

一般的に...ですが、後者の早期リターンの方が良いと言われているので、是非切り分けられる条件は積極的に切り分けていきましょう!

連想配列でindex(現在の処理位置)を取得する方法

さて、ここまで色々とみてきましたが、途中で、連想配列の場合のindexは?と思った方もいらっしゃるかと思います。

実は、通常の配列からindexを取得した時と、連想配列でのkeyの取得をした時の記述は全く一緒でした。

これは、通常の配列では、その配列のvalueのkeyとして、自動的に番号が割り振られます。

そのため、そのvalueのkeyを取得すれば結果的にindex番号が取得できたんです。

ただ、連想配列の場合はすでに何かしらの値がkeyに入っています。

そのため、自動で番号が割り振られることはありません。

ざ〜っと調べた感じだとforeach側の便利な仕組みはなさそうなので、以下で実装してみました。

$practiceTitle = '連想配列のindexを取得する方法';
separator($practiceTitle);
$articleList = [
    'article1' => 'content1', 
    'article2' => 'content2', 
    'article3' => 'content3', 
    'article4' => 'content4'
];
foreach($articleList as $article => $title) {
    // 一度キーのリストを作成し、そのindexの値を用いる
    $keysList = array_keys($articleList);
    $index = array_search($article ,$keysList);
    echo($index . ':' . $article . "のタイトル : " . "$title" . "\n");
}


// 以下出力結果
0:article1のタイトル : content1
1:article2のタイトル : content2
2:article3のタイトル : content3
3:article4のタイトル : content4

ほとんどは前述の連想配列から一件づつ...のものと同様です。

ただ以下の部分が加わった形ですね。

    $keysList = array_keys($articleList);
    $index = array_search($article ,$keysList);

ここでやっていることは、大元となる$articleListのキーのリストを作成します。

これにより以下のような配列ができます。

[
    'article1'
    'article2'
    'article3'
    'article4'
];

この際、ただの配列になってくれるため、前述したindexが自動で割り振られてくれます。

あとは、現在foreachで処理している配列要素のkeyは"$article"として存在しているので、キーのリスト配列からそのキーの値のkey(複雑ですが、キーの値をvalueとして持つ配列なので...)を探せば自動で割り振られたindexの値が取得できる仕組みです。

もちろん0始まりなので、1始まりにする場合はこのindexに1を足してください。

今回は説明のため全ての処理をforeachの中に詰め込みましたが、$keysListの内容は大元の配列の内容をもとにしていて、foreachの各処理で中身が変わりません。

毎回同じ値になるのに毎回キー配列を作るのも無駄なので、foreachの外側で扱った方が適切かと思います。

連想配列の中の配列から値を取得する

$articlesList = [
    'articles1' => ['article1', 'article2', 'article3', 'article4'], 
    'articles2' => ['article1', 'article2', 'article3', 'article4'], 
    'articles3' => ['article1', 'article2', 'article3', 'article4'], 
    'articles4' => ['article1', 'article2', 'article3', 'article4']
];

foreach($articlesList as $articlesKinds => $articles) {
    
    // 一件だけ
    echo($articlesKinds . "の最初の記事 : " . $articles[0]. "\n");
    
    // 全件
    foreach($articles as $article) {
        echo($articlesKinds . "の記事 : " . $article . "\n");
    }

}

// 以下出力結果
articles1の最初の記事 : article1
articles1の記事 : article1
articles1の記事 : article2
articles1の記事 : article3
articles1の記事 : article4
articles2の最初の記事 : article1
articles2の記事 : article1
articles2の記事 : article2
articles2の記事 : article3
articles2の記事 : article4
articles3の最初の記事 : article1
articles3の記事 : article1
articles3の記事 : article2
articles3の記事 : article3
articles3の記事 : article4
articles4の最初の記事 : article1
articles4の記事 : article1
articles4の記事 : article2
articles4の記事 : article3
articles4の記事 : article4

次は連想配列の中に配列が入っている場合です。

複雑にはなってきますが、考えることは簡単です。

foreachの中でindexで配列へアクセスするか、あるいはさらにforeachを回してあげれば全件の取得ができます。

一瞬入れ子の形になっっていると...うっ...となりますが、基本に忠実に考えれば全て理解できるかと思います!

仮に連想配列が入っている場合も大きく変わらないので、今回はここまでにしておきます!

最後に

最後に、今回動作確認をする際に使っていたコードを以下に置いておきます。

一部出力をみやすくするためのコード片も混じっていますが、基本的には説明した内容になっています。

よかったら皆さんも実際に触って動かしてから理解を深めてください!

念の為、以下にリンク先のコピペも置いておきます。

<?php
// Your code here!

$practiceTitle = '配列から一件づつ取得する';
separator($practiceTitle);
$articleList = ['article1', 'article2', 'article3', 'article4'];
foreach($articleList as $article) {
    echo($article . "\n");
}


$practiceTitle = '連想配列から一件づつ取得する例';
separator($practiceTitle);
$articleList = [
    'article1' => 'content1', 
    'article2' => 'content2', 
    'article3' => 'content3', 
    'article4' => 'content4'
];
foreach($articleList as $article => $title) {
    echo($article . "のタイトル : " . "$title" . "\n");
}



$practiceTitle = 'indexも合わせて出力';
separator($practiceTitle);
$articleList = ['article1', 'article2', 'article3', 'article4'];
foreach($articleList as $index => $article) {
    echo($index . ':' . $article . "\n");
}



$practiceTitle = 'indexも合わせて出力(1始まりにする)';
separator($practiceTitle);
$articleList = ['article1', 'article2', 'article3', 'article4'];
foreach($articleList as $index => $article) {
    $beginFromOneIndex = $index+1;
    echo($beginFromOneIndex . ':' . $article . "\n");
}



$practiceTitle = 'breakで2番目まで処理をして止める';
separator($practiceTitle);
$articleList = ['article1', 'article2', 'article3', 'article4'];
foreach($articleList as $index => $article) {
    if($index === 2) { // indexが0,1の処理が行われた後、2でbreakする
        break;
    }
    echo($article . "\n");
}



$practiceTitle = '偶数番目の記事だけ表示する(条件でくくる)';
separator($practiceTitle);
$articleList = ['article1', 'article2', 'article3', 'article4'];
foreach($articleList as $index => $article) {
    if($index % 2 === 1) {
        echo($article . "\n");
    }
}



$practiceTitle = '偶数番目の記事だけ表示する(continue)';
separator($practiceTitle);
$articleList = ['article1', 'article2', 'article3', 'article4'];
foreach($articleList as $index => $article) {
    if($index % 2 === 0) {
        continue;
    }
    echo($article . "\n");
}



$practiceTitle = '連想配列でindexを取得したい場合';
separator($practiceTitle);
$articleList = [
    'article1' => 'content1', 
    'article2' => 'content2', 
    'article3' => 'content3', 
    'article4' => 'content4'
];
$keysList = array_keys($articleList); // キーの配列を準備しておく
foreach($articleList as $article => $title) {
    $index = array_search($article ,$keysList);
    echo($index . ':' . $article . "のタイトル : " . "$title" . "\n");
}



$practiceTitle = '連想配列の中の配列から値を取得する';
separator($practiceTitle);
$articlesList = [
    'articles1' => ['article1', 'article2', 'article3', 'article4'], 
    'articles2' => ['article1', 'article2', 'article3', 'article4'], 
    'articles3' => ['article1', 'article2', 'article3', 'article4'], 
    'articles4' => ['article1', 'article2', 'article3', 'article4']
];
foreach($articlesList as $articlesKinds => $articles) {
    // 一件だけ
    echo($articlesKinds . "の最初の記事 : " . $articles[0]. "\n");
    // 全件
    foreach($articles as $article) {
        echo($articlesKinds . "の記事 : " . $article . "\n");
    }
}



// その他

function separator($practiceTitle) {
    echo('----------------------------------------' . $practiceTitle .  "\n");
}

?>

まとめ

さて、今回は普段よく使うforeach文についていろいろと試してみました!

普段よく使いますが、案外細かくはみないですよね...

breakやcontinueもガッツリ使うか?と言われるとたま〜に出番がくる程度なので、しっかり確認するいい機会になったのかなぁとおもいました。

是非皆さんも初心に立ち返って確認してみてください!

それでわ!

おすすめの記事