PHP PDO с foreach и fetch

Следующие коды:

<?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» дважды не является моей целью, мне просто интересно, почему TWO «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); 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 

Кто-нибудь знает, почему это происходит? Я просто начинающий PHP, спасибо за вашу помощь!

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 с полным кэшем:

 $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/>"; } 

Вы находите класс CachedPDOStatement как сущность . Кэширование itertor, вероятно, более разумно, чем сохранение набора результатов в массив, поскольку он по-прежнему предлагает все свойства и методы объекта PDOStatement он завернул.

foreach over statement – это просто синтаксический сахар для регулярного однонаправленного цикла fetch (). Если вы хотите перебрать свои данные более одного раза, сначала выберите его как обычный массив

 $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

Это потому, что вы читаете курсор, а не массив. Это означает, что вы читаете последовательно результаты, и, когда вы доберетесь до конца, вам нужно будет переустановить курсор в начало результатов, чтобы прочитать их снова.

Если вы хотите прочитать результаты несколько раз, вы можете использовать fetchAll ( http://www.php.net/manual/en/pdostatement.fetchall.php ), чтобы прочитать результаты в настоящий массив, а затем он будет работать как вы ожидаете.

 $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 по которому вы можете выполнять итерацию. Первая итерация выводит все результаты, вторая ничего не делает, поскольку вы можете только перебирать результат один раз. Это потому, что данные передаются из базы данных, и повторение результата с помощью 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 .

В последнем примере вы просто извлекаете первую строку результатов и перебираете ее.