うまくやっているかどうか知りたい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」で機能しないのはなぜですか?
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
}
ただし、警告の言葉:すべてをフェッチすると、まさにそれが実行されます。結果のサイズが大きいと、マシンのリソースに負荷がかかります。これを行うのは、結果セットが小さくなることがわかっている場合、またはクエリに制限を適用して強制する場合のみです。
PHPマニュアルから:
whileステートメントの意味は単純です。 while式がTRUEと評価される限り、ネストされたステートメントを繰り返し実行するようにPHPに指示します。
使用しているメソッド は配列を返すため、while ($row=$page->fetchAll(PDO::FETCH_ASSOC))
は$ rowを結果セット全体の配列に設定します。あなたが期待しているのは、fetchAllメソッドが Iteratorクラス を拡張することですが、そうではありません。
foreach
はここに行く正しい方法です。
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;
私はあなたのケースを再現しようとしました。ここを見て:
<?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
は配列の配列を反復処理し、毎回対応する行があります。
fetchAll
in whileループを使用すると、最初の反復ですべてのレコードがフェッチされ、次回はフェッチするものがありません。 foreach
でも、最初の行のすべてのレコードをフェッチしましたが、foreach
はその結果を反復に使用します。