22

次のコード:

<?php
try {
    $dbh = new PDO("mysql:host=$hostname;dbname=$dbname", $username, $password);
    echo "Connection is successful!<br/>";
    $sql = "SELECT * FROM users";
    $users = $dbh->query($sql);
    foreach ($users as $row) {
        print $row["name"] . "-" . $row["sex"] ."<br/>";
    }
    foreach ($users as $row) {
        print $row["name"] . "-" . $row["sex"] ."<br/>";
    }
    $dbh = null;
}
catch (PDOexception $e) {
    echo "Error is: " . $e-> etmessage();
}

出力:

Connection is successful!

person A-male
person B-female

「foreach」を2回実行することは私の目的ではありません。なぜ、2つの「foreach」ステートメントが結果を1回だけ出力するのか興味があります。

同様のケースは次のとおりです。

<?php
try {
    $dbh = new PDO("mysql:host=$hostname;dbname=$dbname", $username, $password);
    echo "Connection is successful!<br/>";
    $sql = "SELECT * FROM users";
    $users = $dbh->query($sql);
    foreach ($users as $row) {
        print $row["name"] . "-" . $row["sex"] ."<br/>";
    }
    echo "<br/>";
    $result = $users->fetch(PDO::FETCH_ASSOC);
    foreach($result as $key => $value) {
        echo $key . "-" . $value . "<br/>";
    }
    $dbh = null;
}
catch (PDOexception $e) {
    echo "Error is: " . $e-> etmessage();
}

出力:

Connection is successful!

person A-male
person B-female

SCREAM: Error suppression ignored for
Warning: Invalid argument supplied for foreach()

しかし、上記のコードから最初の「foreach」を削除すると、出力は正常になります。

<?php
try {
    $dbh = new PDO("mysql:host=$hostname;dbname=$dbname", $username, $password);
    echo "Connection is successful!<br/>";
    $sql = "SELECT * FROM users";
    $users = $dbh->query($sql);

    echo "<br/>";
    $result = $users->fetch(PDO::FETCH_ASSOC);
    foreach($result as $key => $value) {
        echo $key . "-" . $value . "<br/>";
    }
    $dbh = null;
}
catch (PDOexception $e) {
    echo "Error is: " . $e-> etmessage();
}

出力:

Connection is successful!

user_id-0000000001
name-person A
sex-male

なぜこれが起こるのですか?

4

5 に答える 5

29

A PDOStatement(にある$users)はフォワードカーソルです。つまり、一度消費されると(最初のforeach反復)、結果セットの先頭に巻き戻されません。

の後でカーソルを閉じてforeach、ステートメントを再度実行できます。

$users       = $dbh->query($sql);
foreach ($users as $row) {
    print $row["name"] . " - " . $row["sex"] . "<br/>";
}

$users->execute();

foreach ($users as $row) {
    print $row["name"] . " - " . $row["sex"] . "<br/>";
}

CachingIteratorまたは、fullcacheで調整されたものを使用してキャッシュすることもできます。

$users       = $dbh->query($sql);

$usersCached = new CachedPDOStatement($users);

foreach ($usersCached as $row) {
    print $row["name"] . " - " . $row["sex"] . "<br/>";
}
foreach ($usersCached as $row) {
    print $row["name"] . " - " . $row["sex"] . "<br/>";
}

あなたは要点としてクラスを見つけますCachedPDOStatementPDOStatementキャッシングイテレータは、ラップしたオブジェクトのすべてのプロパティとメソッドを引き続き提供するため、結果セットを配列に格納するよりもおそらく適切です。

于 2013-03-13T13:07:20.847 に答える
18

受け入れられた回答で示唆されているように、すでに得られた結果を得るためだけに同じクエリを再度実行することは狂気です。このような単純なタスクを実行するためにコードを追加することも意味がありません。なぜ人々がそのような原始的で最も基本的な行動を複雑にするためにそのような複雑で非効率的な方法を考案するのか私にはわかりません。

PDOStatementは配列ではありません。ステートメント上での使用は、おなじみの一方向ループを内部的に使用するforeach単なるシンタックスシュガーです。whileデータを複数回ループする場合は、最初に通常の配列として選択するだけです。

$sql = "SELECT * FROM users";
$stm = $dbh->query($sql);
// here you go:
$users = $stm->fetchAll();

次に、この配列を必要な回数だけ使用します。

foreach ($users as $row) {
    print $row["name"] . "-" . $row["sex"] ."<br/>";
}
echo "<br/>";
foreach ($users as $row) {
    print $row["name"] . "-" . $row["sex"] ."<br/>";
}

また、そのことをやめtry..catchます。使用しないでください。ただし、 PHPおよびPDOの適切なエラーレポートを設定してください。

于 2013-03-13T13:27:45.683 に答える
10

これは、配列ではなくカーソルを読み取っているためです。これは、結果を順番に読んでいることを意味し、最後に到達したら、カーソルを結果の最初にリセットして、結果を再度読み取る必要があります。

結果を複数回読みたい場合は、fetchAllを使用して結果を真の配列に読み上げると、期待どおりに機能します。

于 2013-03-13T13:05:07.907 に答える
0
$users = $dbh->query($sql);
foreach ($users as $row) {
    print $row["name"] . "-" . $row["sex"] ."<br/>";
}
foreach ($users as $row) {
    print $row["name"] . "-" . $row["sex"] ."<br/>";
}

これ$usersは、PDOStatement反復できるオブジェクトです。最初の反復ではすべての結果が出力され、2番目の反復では結果を1回しか反復できないため、何も実行されません。これは、データがデータベースからストリーミングされており、結果を反復処理することforeachは、基本的に次の略記であるためです。

while ($row = $users->fetch()) ...

そのループを完了したら、再度ループする前に、データベース側のカーソルをリセットする必要があります。

$users = $dbh->query($sql);
foreach ($users as $row) {
    print $row["name"] . "-" . $row["sex"] ."<br/>";
}
echo "<br/>";
$result = $users->fetch(PDO::FETCH_ASSOC);
foreach($result as $key => $value) {
    echo $key . "-" . $value . "<br/>";
}

ここでは、すべての結果が最初のループによって出力されています。結果セット(上記を参照)をすでに使い果たしているため、への呼び出しfetchはに戻りfalseます。そのため、ループしようとするとエラーが発生しますfalse

最後の例では、最初の結果行をフェッチし、それをループしています。

于 2013-03-13T13:05:51.713 に答える
-2
$row = $db->getAllRecords(DB_TBLPREFIX . '_payplans', '*', ' AND ppid = "' . $myid . '"');
foreach ($row as $value) {
    $bpprow = array_merge($bpprow, $value);
}

これは、このデータをグローバルに使用できるPHP関数に基づいています。

于 2022-02-15T08:55:53.850 に答える