尝试catch块不适用于pdo语句和foreach

尝试catch块不适用于pdo语句和foreach

本文介绍了尝试catch块不适用于pdo语句和foreach的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近,我鼓励使用PHP代码中的怪异错误.就像将PDOStatement对象与foreach(){}一起使用时,会忽略内部的try{}catch(){}块.这是触发此行为的测试代码:

Recently I've encouraged weird error in PHP code. It's like the inner try{}catch(){} block is omited when using PDOStatement object with foreach(){}. Here is my test code which triggers this behaviour:

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

这在我的本地主机(带有Suhosin-Patch(cli)的PHP 5.3.6-13ubuntu3.6)和服务器(PHP 5.2.17)上输出如下内容:

This outputs something like this on my localhost (PHP 5.3.6-13ubuntu3.6 with Suhosin-Patch (cli)) and on server (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){时,一切都按预期进行:

Don't know why but when I change foreach($sth as $row){ to foreach($sth->fetchAll() as $row){ everythings works as expected:

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

我是否发现了错误或我做错了什么?有人可以确认这种行为吗?谢谢

Did I found a bug or am I doing something wrong? Can someone confirm that behaviour? Thx

//编辑

将PHP版本升级到5.3.10似乎可以解决此问题.寻求帮助...

Upgrading PHP version to 5.3.10 seems to fix this issue. Thx for help...

推荐答案

不,您不能直接从PDO返回的结果进行迭代.这不是PDO例外,当您尝试执行此操作时,它是PHP,它不是具有迭代器的数组或对象.

No, the result sent back from PDO is not something you can directly iterate over. It's not a PDO exception, it's a PHP when you try to do that--it's not an array or an object that has an iterator.

获取时会创建一个在foreach循环中有效的数组.

When you fetch it creates an array that is valid in the foreach loop.

这篇关于尝试catch块不适用于pdo语句和foreach的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-26 07:39