質問をすることでしか得られない、回答やアドバイスがある。

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

ただいまの
回答率

89.20%

foreach文とfor文について

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,996

aaaaaaaa

score 481

下記のソースは、書籍(気づけばプロ並みPHP)を参考に作成したショッピングカートの買い物かごにあたる部分の処理です。
foreach文を使って、データベース上にある商品をとりだし、foreach文の中で商品を表示しています。
しかし参考書には、foreach文で商品を表示することはよくないのでforeachから分離し別途for文で表示するように書いてありました。理由は、「表示したい配列が一つならforeachで構わないが、配列変数が複数あるためfor文を使うべき」とのことです。、foreach文だけでも問題なく商品は表示されているし、理由で挙げられている、単数ならforeach、複数ならforという区分けもいくつかの参考書を手に取ってみましたが解かりませんでした。

なぜ、foreach文ではなくfor文で商品を表示させるのでしょうか。
require_once "../lib/dbaccess.php";

$cart = $_SESSION['cart'];
//$_SESSION['cart']は、$cart配列がどのページでも使えるようにしたものだ。中身は、商品に関する情報を管理する一意の商品番号が入っている。
foreach($cart as $key => $val) {
    
$dbh = dbaccess();    
//mst_productテーブルに商品の番号、名前、価格、画像が入っている。
$sql = 'SELECT * FROM mst_product WHERE code=?';
$stmt = $dbh->prepare($sql);
//$valは、$_SESSION['cart']に代入された商品番号が代入されている。
$data[0] = $val;
$stmt->execute($data);
$dbh = null;

$rec = $stmt->fetch(PDO::FETCH_ASSOC);
echo <<<EOL

<p>{$rec['code']}</p>
<p>{$rec['name']}</p>
<p>{$rec['price']}</p>
EOL;
if(!$rec['gazou'] == '') {
 print'<p><img src="../product/gazou/'.$rec['gazou'].'"></p>';
}
print'<hr>';


}//foreach
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q11151770801

申し訳ありませんでした。書き損じておりました。
参考にした書籍の内容は第二版で、ページは184Pです。
提示してあるソースは、内容を見る前に自身で作成したものを184pに掲載されているソースで加味したものであります。
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • KiyoshiMotoki

    2015/10/23 21:57

    書籍を確認し、それらしい記述を見つけたのですが、ご提示いただいたソースコードと書籍に載っているものが異なるため、確証が持てません。

    第二版の184ページで、間違いないでしょうか?

    キャンセル

回答 2

checkベストアンサー

+1

情報の追記、ありがとうございます。

今、手元に書籍がないので思い出しながら回答させていただきます。

該当ページのソースコードでは、foreach文の中で1行ずつDBから取り出したデータを
$pro_name$pro_price$pro_gazou
という3つの配列変数に格納していました。

以下のような感じだったと思います。
foreach($cart as $key => $val) {

    $dbh = dbaccess();    
    //mst_productテーブルに商品の番号、名前、価格、画像が入っている。
    $sql = 'SELECT * FROM mst_product WHERE code=?';
    $stmt = $dbh->prepare($sql);
    //$valは、$_SESSION['cart']に代入された商品番号が代入されている。
    $data[0] = $val;
    $stmt->execute($data);
    $dbh = null;

    $rec = $stmt->fetch(PDO::FETCH_ASSOC);


    $pro_name[] = $rec['name'];
    $pro_price[] = $rec['price'];
    $pro_gazou[] = is_null($rec['gazou']) ? '' : $rec['gazou'];
}

で、これら3つの変数に格納された値をWEBページに表示しようとする際に
foreach文で商品を表示することはよくない(または、できない)
という趣旨の記述が(理由を説明することもなくw)あったと思います。

私の想像では、ここで著者が言いたいことは
foreach文では同時に2つ以上の配列に逐次アクセスすることができないため」
ではないかと思います。
// このようなことはできない。
foreach ($pro_name as $name, $pro_price as $price, $pro_gazou as $gazou) {
    echo "名前は" . $name . "<br>";
    echo "値段は" . $price . "<br>";
    echo "<img src='" . $gazou . "'";
}

なので、代わりにfor文を使用することを推奨しているわけです。
for文なら、複数の配列変数に同時に逐次アクセスできますので。
// これは可能。
for ($i = 0; $i < count($pro_name); $i++) {
    echo "名前は" . $pro_name[$i] . "<br>";
    echo "値段は" . $pro_price[$i] . "<br>";
    echo "<img src='" . $pro_gazou[$i] . "'";
}

※質問を投稿する際は、なるべく精確かつ詳細に情報を載せて下さい。
  今回のように記述されている箇所を特定できなかったり
  そもそも書籍に書かれているのとは異なるソースコードを載せられたりすると、
  回答できないばかりか、見当違いな回答をしてしまう可能性がありますので。
  それは、お互いにとって不幸なことです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/10/27 20:10

    ご回答有難うございます。とても分かりやすい解説で理解できました。
    >>「foreach文では同時に2つ以上の配列に逐次アクセスすることができないため」
    無理やりforeachにしようとすると、pro_name用、pro_price用、pro_gazou用のforeachが必要になってしまうので、一つで上手くいくforで済ませようとしたということなのですね。

    質問文に関しては重ね重ね申し訳ありませんでした。

    キャンセル

  • 2015/10/27 20:43

    > 無理やりforeachにしようとすると、pro_name用、pro_price用、pro_gazou用のforeachが必要になってしまうので、一つで上手くいくforで済ませようとしたということなのですね。

    はい、おっしゃる通りです。

    キャンセル

+1

引用テキストしかし参考書には、foreach文で商品を表示することはよくないのでforeachから分離し別途for文で表示するように書いてありました。理由は、「表示したい配列が一つならforeachで構わないが、配列変数が複数あるためfor文を使うべき」とのことです。、foreach文だけでも問題なく商品は表示されているし、理由で挙げられている、単数ならforeach、複数ならforという区分けもいくつかの参考書を手に取ってみましたが解かりませんでした。 
上記の文章からは私も理由がわかりませんでした。
ループ処理を行う場合に通常はfor/foreachどちらを使うべきという事はありません。

プログラムを拝見すると1点問題がありますので、書籍ではそちらを懸念しているのかもしれません。
例示されたものではforeachループの中でDBから1つずつデータを取ってきていますので、
例えば100アイテムある場合はSELECTを100回発行することになります。
これはデータベースに連続で負荷をかける為、全データを1回でSELECTする形に改善するべきです。
簡単に例示すると以下のようになります。(エラー処理等は省いています)

require_once "../lib/dbaccess.php";

$cart = $_SESSION['cart'];

//配列が空か?
if (!is_array($cart) || count($cart) < 1) die("NODATA");

//mst_productテーブルに商品の番号、名前、価格、画像が入っている。
$dbh = dbaccess();
$sql = 'SELECT * FROM mst_product WHERE code in ('.str_repeat('?,', count($cart)-1).'?)';
$stmt = $dbh->prepare($sql);
//$cart[n]='商品コード'の形で記録されていると仮定
$stmt->execute($cart);
$items = $stmt->fetchAll(PDO::FETCH_ASSOC);
$dbh = null;

//$_SESSION['cart']は、$cart配列がどのページでも使えるようにしたものだ。中身は、商品に関する情報を管理する一意の商品番号が入っている。
foreach($items => $rec) {
echo <<<EOL

<p>{$rec['code']}</p>
<p>{$rec['name']}</p>
<p>{$rec['price']}</p>
EOL;
if(!$rec['gazou'] == '') {
 print'<p><img src="../product/gazou/'.$rec['gazou'].'"></p>';
}
print'<hr>';


}//foreach

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/10/27 20:14

    ご回答有難うございます。

    >>プログラムを拝見すると1点問題...
    質問だけでなく別の問題点まで指摘してくださって有難うございます。
    ループ内でDBに接続したりプリペアドステートメントを作ったり、ととても迂闊でした。勉強になります。

    キャンセル

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

  • ただいまの回答率 89.20%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる