web-dev-qa-db-fra.com

PHP AOP avec foreach et fetch

Les codes suivants:

<?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();
}

SORTIE:

Connection is successful!

person A-male
person B-female

Exécuter "foreach" deux fois n’est pas mon but, je suis juste curieux de savoir pourquoi DEUX déclarations "foreach" ne produisent le résultat qu’une fois?

Voici le cas similaire:

<?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();
}

SORTIE:

Connection is successful!

person A-male
person B-female

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

Mais lorsque je supprime le premier "foreach" des codes ci-dessus, le résultat devient normal:

<?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();
}

SORTIE:

Connection is successful!

user_id-0000000001
name-person A
sex-male

Quelqu'un sait pourquoi cela se produit-il? Je ne suis qu'un débutant PHP, merci pour votre aide!

15
nut

Une PDOStatement (que vous avez dans $users) est un curseur avant. Cela signifie que, une fois consommée (la première itération foreach), elle ne reviendra pas au début du jeu de résultats.

Vous pouvez fermer le curseur après la foreach et exécuter à nouveau l'instruction:

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

Ou vous pouvez mettre en cache en utilisant CachingIterator sur mesure avec un 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/>";
}

Vous trouvez la classe CachedPDOStatement sous forme de Gist . L'iterteur de mise en cache est probablement plus sain que de stocker le jeu de résultats dans un tableau car il offre toujours toutes les propriétés et méthodes de l'objet PDOStatement qu'il a encapsulé.

19
hakre

foreach sur une instruction est juste un sucre de syntaxe pour la boucle unidirectionnelle régulière fetch (). Si vous souhaitez parcourir vos données plusieurs fois, sélectionnez-les d'abord en tant que tableau standard.

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

Quittez également cette chose try..catch. Ne l'utilisez pas, mais configurez le rapport d'erreur approprié pour PHP et PDO

11
Your Common Sense

C'est parce que vous lisez un curseur et non un tableau. Cela signifie que vous lisez les résultats de manière séquentielle et que lorsque vous arrivez à la fin, vous devez réinitialiser le curseur au début des résultats pour les relire.

Si vous voulez lire les résultats plusieurs fois, vous pouvez utiliser fetchAll ( http://www.php.net/manual/en/pdostatement.fetchall.php ) pour lire les résultats dans un vrai tableau alors cela fonctionnerait comme vous l'attendez.

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

Ici, $users est un objet PDOStatement sur lequel vous pouvez effectuer une itération. La première itération affiche tous les résultats, la seconde ne fait rien car vous ne pouvez parcourir le résultat qu'une seule fois. En effet, les données sont en cours de flux depuis la base de données et l'itération du résultat avec foreach est essentiellement un raccourci pour:

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

Une fois que vous avez terminé cette boucle, vous devez réinitialiser le curseur du côté base de données avant de pouvoir le parcourir à nouveau.

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

Ici, tous les résultats sont générés par la première boucle. L'appel à fetch renverra false, puisque vous avez déjà épuisé le jeu de résultats (voir ci-dessus), vous obtenez donc une erreur lorsque vous essayez de boucler false.

Dans le dernier exemple, vous récupérez simplement la première ligne de résultat et la parcourez en boucle.

0
deceze