web-dev-qa-db-ja.com

php PDO fetchAll()-機能していない間、foreachは機能します

うまくやっているかどうか知りたいOR fetchAll()がWHILEで動作しない。

ここに例があります

$db=new PDO("mysql:Host=" .$dbhost. "; dbname=" . $dbname, $dbuser, $dbpass);

$page=$db->prepare("SELECT * FROM page");
$page->execute();

foreach ($page->fetchAll(PDO::FETCH_ASSOC) as $row) {

//echo a row
//is working
}

しかし、私はしばらくループしようとすると

while ($row=$page->fetchAll(PDO::FETCH_ASSOC)){

//echo a row
//Show empty
}

私はfetch()のみを使用しようとしましたが、機能していました。私の質問:fetchAll()が「WHILE」で機能しないのはなぜですか?

5
Mafitsi

Fetch allは、結果セットに残っているすべてのレコードを返します。これを念頭に置いて、foreachは期待どおりに結果セットを反復処理できます。

同等のwhile実装では、$page->fetch(PDO::FETCH_ASSOC);を使用する必要があります

while ($row = $page->fetch(PDO::FETCH_ASSOC)){
   // do something awesome with row
} 

しばらく使って、できることをすべてフェッチしたい場合

$rows = $page->fetchAll(PDO::FETCH_ASSOC);

// use array_shift to free up the memory associated with the record as we deal with it
while($row = array_shift($rows)){
   // do something awesome with row
}

ただし、警告の言葉:すべてをフェッチすると、まさにそれが実行されます。結果のサイズが大きいと、マシンのリソースに負荷がかかります。これを行うのは、結果セットが小さくなることがわかっている場合、またはクエリに制限を適用して強制する場合のみです。

18
Orangepill

PHPマニュアルから:

whileステートメントの意味は単純です。 while式がTRUEと評価される限り、ネストされたステートメントを繰り返し実行するようにPHPに指示します。

使用しているメソッド は配列を返すため、while ($row=$page->fetchAll(PDO::FETCH_ASSOC))は$ rowを結果セット全体の配列に設定します。あなたが期待しているのは、fetchAllメソッドが Iteratorクラス を拡張することですが、そうではありません。

foreachはここに行く正しい方法です。

7
Tyler V.

fetchAll --well --fetchs all 1つのコマンドでレコードを取得するため、レコードセットをループする必要はありません。いいですね。

$rows = $page->fetchAll(PDO::FETCH_ASSOC);

// $rows is an array containing all records...
foreach ($rows as $row)
    echo $row->fieldname;
4
michi

私はあなたのケースを再現しようとしました。ここを見て:

script.php

<?php
$Host = 'localhost';
$user = "user";
$password = '';
$db_name = 'test';
$port = 3306;

try
{
    $connection = new PDO("mysql:Host=$Host;port=$port;dbname=$db_name", $user, $password);
    $connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e)
{
    echo 'Connection failed: ' . $e->getMessage();
}

$page=$connection->prepare("SELECT * FROM Document");
$page->execute();

while ($row = $page->fetchAll(PDO::FETCH_ASSOC)) {
    var_dump($row);
}

データベーステスト

DROP TABLE IF EXISTS `Document`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `Document` (
  `DataID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `Description` varchar(50) CHARACTER SET utf8 NOT NULL,
  PRIMARY KEY (`DataID`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `Document`
--

LOCK TABLES `Document` WRITE;
/*!40000 ALTER TABLE `Document` DISABLE KEYS */;
INSERT INTO `Document` VALUES (1,'!!!'),(2,'This is document 2'),(3,'This is document 3'),(4,'This is document 4'),(5,'Hello');
/*!40000 ALTER TABLE `Document` ENABLE KEYS */;
UNLOCK TABLES;

出力

$php script.php
array(5) {
  [0]=>
  array(2) {
    ["DataID"]=>
    string(1) "1"
    ["Description"]=>
    string(3) "!!!"
  }
  [1]=>
  array(2) {
    ["DataID"]=>
    string(1) "2"
    ["Description"]=>
    string(18) "This is document 2"
  }
  [2]=>
  array(2) {
    ["DataID"]=>
    string(1) "3"
    ["Description"]=>
    string(18) "This is document 3"
  }
  [3]=>
  array(2) {
    ["DataID"]=>
    string(1) "4"
    ["Description"]=>
    string(18) "This is document 4"
  }
  [4]=>
  array(2) {
    ["DataID"]=>
    string(1) "5"
    ["Description"]=>
    string(5) "Hello"
  }
}

出力は、ステートメントが1回実行され、すべての行が出力される間、クエリが返される必要があることを意味します。これは、fetchAllがすべての行を含む配列の配列を返すため、絶対に正しいことです。 PHPはそれをtrueとして解釈し、whileは1回実行されます。

foreachは配列の配列を反復処理し、毎回対応する行があります。

2
user4035

fetchAll in whileループを使用すると、最初の反復ですべてのレコードがフェッチされ、次回はフェッチするものがありません。 foreachでも、最初の行のすべてのレコードをフェッチしましたが、foreachはその結果を反復に使用します。

0
bansi