0
最近我鼓勵PHP代碼中的奇怪錯誤。這就像使用foreach(){}
使用PDOStatement對象時,內部的塊將被忽略。這裏是一個觸發這個行爲我的測試代碼:嘗試catch塊不能與pdo語句和foreach一起使用
<?php
/*
// THIS WORKS AS EXPECTED, JUST UNCOMMENT
try{
for($i = 0; $i < 3; $i++){
try{
echo "\nTHROWING EXCEPTION\n\n";
throw new Exception("AAAAAAAAAAAAAAAAAAAAAAAAA");
echo "EXCETION THROWN (SHOULD NOT SHOW)\n";
}catch(Exception $err){
echo "========= INNER CATCH =========\n";
echo $err->getMessage() . "\n";
}
}
}catch(Exception $e){
echo "=========== OUTER CATCH ===========\n";
die($e->getMessage() . "\n");
}
die("\nEVERYTHING OK\n");
*/
$dsn = "mysql:dbname=test_pdo;host=localhost";
try {
$dbh = new PDO($dsn, 'root', "", array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh->exec("
CREATE TABLE IF NOT EXISTS `test` (
`id` int(10) unsigned NOT NULL,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
");
$dbh->exec("TRUNCATE test");
$dbh->exec("
INSERT INTO test (id, name) VALUES
(1, 'JOHN DOE 1'), (2, 'JOHN DOE 2'),
(3, 'JOHN DOE 3'), (4, 'JOHN DOE 4')
");
echo "\nRECORDS CREATED\n";
$sth = $dbh->prepare("SELECT id FROM test WHERE id = ?");
foreach(array(2, 3, 4) as $id){
$sth->execute(array($id));
$i = 0;
foreach($sth as $row){
$num = $row['id'] - 1;
// this sql should throw 2300 error duplicate key
$sql = "UPDATE test SET name = 'JOHN DOE $num' WHERE id = {$row['id']}";
try{
echo "\nSENDING QUERY: $sql\n\n";
$dbh->exec($sql);
}catch(Exception $err){
$code = $err->getCode();
$msg = $err->getMessage();
//duplicate key error?
if($err->getCode() != "23000"){
echo "THROWING EXCEPTION FROM INNER CATCH.\n ERROR CODE: $code\n";
throw $err;
}
echo <<<TXT
============ GOOD CATCH ============
ERROR CODE: $code
ERROR MSG: $msg
SQL: $sql
TXT;
}
}
}
}catch(Exception $e){
$code = $e->getCode();
$msg = $e->getMessage();
echo <<<TXT
============ WRONG CATCH ===========
ERROR CODE: $code
ERROR MSG: $msg
TXT;
}
此輸出這樣的事情在我的本地(PHP 5.3.6-13ubuntu3.6用了Suhosin貼片(CLI))和服務器(PHP 5.2.17 ):
RECORDS CREATED
SENDING QUERY: UPDATE test SET name = 'JOHN DOE 1' WHERE id = 2
============ GOOD CATCH ============
ERROR CODE: 23000
ERROR MSG: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'JOHN DOE 1' for key 'name'
SQL: UPDATE test SET name = 'JOHN DOE 1' WHERE id = 2
============ WRONG CATCH ===========
ERROR CODE: 23000
ERROR MSG: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'JOHN DOE 1' for key 'name'
不知道爲什麼,但是當我改變foreach($sth as $row){
到foreach($sth->fetchAll() as $row){
萬物按預期工作:
RECORDS CREATED
SENDING QUERY: UPDATE test SET name = 'JOHN DOE 1' WHERE id = 2
============ GOOD CATCH ============
ERROR CODE: 23000
ERROR MSG: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'JOHN DOE 1' for key 'name'
SQL: UPDATE test SET name = 'JOHN DOE 1' WHERE id = 2
SENDING QUERY: UPDATE test SET name = 'JOHN DOE 2' WHERE id = 3
============ GOOD CATCH ============
ERROR CODE: 23000
ERROR MSG: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'JOHN DOE 2' for key 'name'
SQL: UPDATE test SET name = 'JOHN DOE 2' WHERE id = 3
SENDING QUERY: UPDATE test SET name = 'JOHN DOE 3' WHERE id = 4
============ GOOD CATCH ============
ERROR CODE: 23000
ERROR MSG: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'JOHN DOE 3' for key 'name'
SQL: UPDATE test SET name = 'JOHN DOE 3' WHERE id = 4
難道我發現了一個錯誤還是我做錯了什麼?有人可以確認這種行爲嗎? THX
// 編輯
升級PHP版本5.3.10似乎解決了這個問題。 Thx尋求幫助...
'PDOStatement'實現了'Traversable'(http://www.php.net/manual/pl/class.traversable.php),所以它可以與foreach一起使用,還是我在這裏錯了? – piotrekkr 2012-03-08 22:50:05