🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

1回答

1297閲覧

[PHP]foreachの挙動とその理由がわからないので解説お願いします。

Buretan

総合スコア33

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2019/11/04 15:36

DBから取得したデータ同士を組み合わせた文字列を出力しようとしています。
foreachの挙動について疑問が出たので質問させていただきます。

以下
・使用DB

次に
・コード1
・出力内容1(意図した挙動)

その次に
・コード2
・出力内容2(意図していない挙動)
を記載いたします。


使用DB テーブル名[test]

mysql

1name1 |name2 2------- 3テスト |うんこ 4りんご |おれんじ 5たろいも|やむいも

コード1

php

1<?php 2$n1=1; 3$n2=1; 4$n3=1; 5 6try { 7 for($n3=1;$n3<4;$n3++){ 8 $sql2 = "SELECT name2 FROM test where id=$n3"; 9 $res2 = $pdo->query($sql2); 10 11 for($n2=1;$n2<4;$n2++){ 12 $sql = "SELECT name1 FROM test where id=$n2"; 13 $res = $pdo->query($sql); 14 $result = $res->fetch(PDO::FETCH_ASSOC); 15 $name2="$result[name1]"; 16 17 for($n1=1;$n1<4;$n1++){ 18 $sql = "SELECT name1 FROM test where id=$n1"; 19         $res = $pdo->query($sql); 20 $result = $res->fetch(PDO::FETCH_ASSOC); 21 $name1="$result[name1]"; 22 $res2 = $pdo->query($sql2); 23 24 foreach($res2 as $value){ 25 echo $name1.$name2."$value[name2]<br>"; 26 } 27 } 28 } 29 } 30} catch (PDOException $e){ 31 echo $e->getMessage(); 32 die(); 33} 34$pdo = null; 35?>

出力内容1

テストテストうんこ りんごテストうんこ たろいもテストうんこ テストりんごうんこ りんごりんごうんこ たろいもりんごうんこ テストたろいもうんこ りんごたろいもうんこ たろいもたろいもうんこ テストテストおれんじ りんごテストおれんじ たろいもテストおれんじ テストりんごおれんじ りんごりんごおれんじ たろいもりんごおれんじ テストたろいもおれんじ りんごたろいもおれんじ たろいもたろいもおれんじ テストテストやむいも りんごテストやむいも たろいもテストやむいも テストりんごやむいも りんごりんごやむいも たろいもりんごやむいも テストたろいもやむいも りんごたろいもやむいも たろいもたろいもやむいも

こちらで意図したとおりに動いてはいます。
次に、問題のコード2と出力内容2です。

コード2

php

1<?php 2$n1=1; 3$n2=1; 4$n3=1; 5 6try { 7 for($n3=1;$n3<4;$n3++){ 8 $sql2 = "SELECT name2 FROM test where id=$n3"; 9 $res2 = $pdo->query($sql2); 10 11 for($n2=1;$n2<4;$n2++){ 12 $sql = "SELECT name1 FROM test where id=$n2"; 13 $res = $pdo->query($sql); 14 $result = $res->fetch(PDO::FETCH_ASSOC); 15 $name2="$result[name1]"; 16 17 for($n1=1;$n1<4;$n1++){ 18 $sql = "SELECT name1 FROM test where id=$n1"; 19         $res = $pdo->query($sql); 20 $result = $res->fetch(PDO::FETCH_ASSOC); 21 $name1="$result[name1]"; 22 23 foreach($res2 as $value){ 24 echo $name1.$name2."$value[name2]<br>"; 25 } 26 } 27 } 28 } 29} catch (PDOException $e){ 30 echo $e->getMessage(); 31 die(); 32} 33$pdo = null; 34?>

コード1との違いはforeachの手前の
$res2 = $pdo->query($sql2);
を消しています。

出力内容2

テストテストうんこ テストテストおれんじ テストテストやむいも

もともとはコード2を最初に動作確認し、コード1に変更したらうまくいったという内容なのですが、なぜそうなったのかがわからないため質問させていただきました。

調べたこと
php.netのforeach解説

ここの解説を見てunset()でforeachのポインタをリセットしないといけないのかな?と思っているのですが、どこに入れたらいいのか理解できませんでした。

試したこと
for文のループ中に何回目のループか出力するコードを入れて動作確認

php

1//中略 2 for($n1=1;$n1<4;$n1++){ 3 $sql = "SELECT name1 FROM test where id=$n1"; 4 $res = $pdo->query($sql); 5 $result = $res->fetch(PDO::FETCH_ASSOC); 6 $name1="$result[name1]"; 7 echo $n1."回目"; //←追加 8//中略

これで動作を確認したところ、foreachのループ後に再度foreachに来るとスルーされている(?)ことがわかりました。

出力内容3

1回目テストテストうんこ 2回目3回目1回目2回目3回目1回目2回目3回目1回目テストテストおれんじ 2回目3回目1回目2回目3回目1回目2回目3回目1回目テストテストやむいも 2回目3回目1回目2回目3回目1回目2回目3回目

知りたいこと
foreachの挙動が出力内容2や3のようになる理由がわからないため、ご教授のほどよろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

リセットが必要なのは$res2です。

$res2は$n3のループ(一番外のループ)でqueryされていますが、そこからforeachで結果セットを最後まで取り出したらそれ以上の結果は得られませんので、$n1のループ(一番内のループ)を3回くりかえしても、2回目以降ではforeachにわたした$res2が$valueを1つも出してくれないので、foreachは0周して終わります。

foreachはスキップされていません。

1がうまくいくのは、foreachの直前にqueryをすることで、$res2の結果セットがリセットされてまた最初から取り出せるようになっているからです。

(この操作をリセットとは言わないような気がしますが、かといって正しい呼び方をしらないので、質問者様の用語に倣いました)

投稿2019/11/04 16:56

papinianus

総合スコア12705

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Buretan

2019/11/05 00:14

回答ありがとうございます。 foreachを1周して外に出た後に二回目のforeachをしても、queryしないとforeachは$valueを返してくれないということでしょうか? 1回目のforeachを抜けた後にvar_dump($value),var_dump($res2)をechoして中身を見てみたのですが、中身自体は残っていたので、疑問が出てきました。
papinianus

2019/11/05 14:48

$res2の中身が見えるというのを確認したことないので回答が間違っているのかもしれませんが、だいたいご理解いただいたのと似た考えでの回答でした
Buretan

2019/11/05 21:12

了解です 回答ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問