2013-03-13 22 views
13

Các mã sau đây:PHP PDO với foreach và lấy

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

OUTPUT:

Connection is successful! 

person A-male 
person B-female 

Chạy "foreach" hai lần không phải là mục đích của tôi, tôi chỉ tò mò tại sao HAI "foreach" báo cáo chỉ xuất kết quả một lần?

Tiếp theo là trường hợp tương tự:

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

OUTPUT:

Connection is successful! 

person A-male 
person B-female 

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

Nhưng khi tôi xóa các "foreach" đầu tiên từ các mã trên, sản lượng sẽ trở nên bình thường:

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

OUTPUT:

Connection is successful! 

user_id-0000000001 
name-person A 
sex-male 

Bất kỳ ai biết tại sao điều này lại xảy ra? Tôi chỉ là người mới bắt đầu sử dụng PHP, cảm ơn sự giúp đỡ của bạn!

Trả lời

17

A PDOStatement (bạn có trong $users) là con trỏ tiến. Điều đó có nghĩa, một khi đã tiêu thụ (lần đầu tiên foreach lặp lại), nó sẽ không tua lại phần đầu của tập kết quả.

Bạn có thể đóng con trỏ sau khi foreach và thực hiện báo cáo kết quả một lần nữa:

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

Hoặc bạn có thể bộ nhớ cache bằng cách sử dụng phù hợp CachingIterator với một 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/>"; 
} 

Bạn find the CachedPDOStatement class as a gist. Các itertor bộ nhớ đệm có lẽ là lành mạnh hơn lưu trữ resultset vào một mảng bởi vì nó vẫn cung cấp tất cả các thuộc tính và phương pháp của đối tượng PDOStatement nó đã bao bọc.

+0

cảm ơn vì đã đề cập đến "chuyển tiếp con trỏ", tôi sẽ google. – nut

+0

Cảm ơn, mặc dù tôi không hiểu rõ nhưng ví dụ của bạn chắc chắn hữu ích cho tôi trong tương lai. – nut

+0

Vui lòng xem thêm một chỉnh sửa khác, tôi đã có lỗi đánh máy: Sử dụng '$ users-> execute();' sau 'foreach' đầu tiên để đặt lại con trỏ về đầu tập hợp kết quả. Điều này rất có thể là những gì bạn đang tìm kiếm. Cache là một giải pháp cụ thể hơn và không thực sự cần thiết vì bạn có thể thực hiện '$ users-> execute();'. Tôi đã thêm nó chỉ cho ví dụ chung. – hakre

8

Điều này là do bạn đang đọc con trỏ không phải là mảng. Điều này có nghĩa là bạn đang đọc tuần tự thông qua các kết quả và khi bạn kết thúc, bạn sẽ cần đặt lại con trỏ về đầu kết quả để đọc lại chúng.

Nếu bạn muốn đọc kết quả nhiều lần, bạn có thể sử dụng fetchAll (http://www.php.net/manual/en/pdostatement.fetchall.php) để đọc kết quả vào một mảng thực và sau đó nó sẽ hoạt động như bạn đang mong đợi.

0
$users = $dbh->query($sql); 
foreach ($users as $row) { 
    print $row["name"] . "-" . $row["sex"] ."<br/>"; 
} 
foreach ($users as $row) { 
    print $row["name"] . "-" . $row["sex"] ."<br/>"; 
} 

Đây $users là đối tượng mà bạn có thể lặp lại. Lần lặp đầu tiên đầu ra tất cả các kết quả, thứ hai không làm gì vì bạn chỉ có thể lặp qua kết quả một lần. Đó là bởi vì các dữ liệu đang được xem trực tiếp từ cơ sở dữ liệu và iterating trên kết quả với foreach thực chất là viết tắt cho:

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

Khi bạn đã hoàn thành vòng lặp đó, bạn cần phải thiết lập lại con trỏ về phía cơ sở dữ liệu trước khi có thể lặp lại nó một lần nữa.

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

Ở đây tất cả kết quả đang được xuất bởi vòng đầu tiên. Cuộc gọi tới fetch sẽ trả lại false, vì bạn đã cạn kiệt tập hợp kết quả (xem ở trên), vì vậy bạn gặp lỗi khi cố gắng lặp lại trên false.

Trong ví dụ cuối cùng, bạn chỉ cần tìm nạp hàng kết quả đầu tiên và đang lặp qua nó.

10

foreach qua tuyên bố chỉ là một đường cú pháp cho vòng lặp tìm nạp một chiều thông thường(). Nếu bạn muốn lặp lại dữ liệu của mình nhiều lần, hãy chọn nó làm một mảng thông thường trước tiên

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

Cũng bỏ điều đó try..catch điều. Không sử dụng, nhưng đặt báo cáo lỗi thích hợp cho PHP và PDO

+0

Cảm ơn bạn đã có mẹo, học cách chuẩn bị và thực hiện là bước tiếp theo của tôi. – nut

+4

@YourCommonSense Tại sao bạn có hai cho mỗi vòng trong câu trả lời của bạn? Tôi không tìm thấy lỗi, chỉ cần học tập ... – Norman

+3

sử dụng pdo-> query() chắc chắn KHÔNG phải là một cách sai lầm khi sử dụng thư viện. exec() và truy vấn() là có để được sử dụng. Cách sử dụng sai duy nhất là cố gắng đi qua câu lệnh hai lần, anh ta chỉ cần fetchAll() và sau đó anh ta có thể lặp lại nhiều lần thông qua mảng .. Nếu bạn ở lại từ của mình, sử dụng truy vấn() là sai, đưa ra lý do chính đáng. – John