it-swarm.com.ru

PHP PDO с 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/>";
    }
    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" дважды не является моей целью, мне просто любопытно, почему ДВЕ операторы "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, спасибо за вашу помощь!

15
nut

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 как Gist . Кэширующий итертор, вероятно, более разумен, чем сохранение набора результатов в массиве, поскольку он по-прежнему предлагает все свойства и методы обернутого объекта PDOStatement.

19
hakre

foreach над оператором - это просто синтаксический сахар для обычного одностороннего цикла 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

11
Your Common Sense

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

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

8
Kevin Garman
$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.

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

0
deceze