PDO catch PDOException fails on construction

2019-03-05 16:42发布

I've seen variations of this code all over the place, including many S.O. posts:

class db extends PDO {

    public function __construct( $dbconf ) {
        $options = array(
            PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_PERSISTENT => $dbconf['persist'] ? true : false
            );
        try {
            parent::__construct('mysql:host='. $dbconf['dbhost'] .';port=3306;dbname='. $dbconf['dbname'] .';' , $dbconf['dbuser'],
                $dbconf['dbpass'],
                $options);
        } catch (PDOException $e) {
            $this->myerror( $e->getMessage() );
            // echo 'Connection failed ... '. $e->getMessage();
        }
    }

    ...

    private function myerror( $error ) {
        echo 'Connection failed ... '. $error;
    }

}

The class is instantiated with $db = new db( $config );, and it works great if the connection is valid, but it seems PDOException doesn't actually work if the connection fails. The catch totally fails to execute the $this->myerror(...) function! Instead of the useful $e->getMessage() that says "Connection failed ... Access denied for user blah", I get a PHP Fatal error: Call to a member function myerror() on a non-object in /.../lib/pdo.class.php on line 16.

If I comment out the first line in the catch and uncomment the echo, it works as expected, reporting the reason for the connection error. Why would the message be available in the catch but not in the simple myerror class function?

This post ... PHP, PDO, and Exceptions ... seems applicable, but doesn't explain much. Is catch (PDOException $e) obsolete, or dysfunctional under certain circumstances? How do I keep get this to work?

标签: php class pdo
2条回答
贪生不怕死
2楼-- · 2019-03-05 17:09

There shouldn't be myerror() function at all. A database layer scarcely need it's own error handler. And constructor have to be

public function __construct( $dbconf ) {
    $dsn  = "mysql:";
    $dsn .= "host=".   $dbconf['dbhost'].";";
    $dsn .= "dbname=". $dbconf['dbname'].";";
    $dsn .= "port=".   $dbconf['dbport'].";";
    $dsn .= "charset=".$dbconf['dbcharset'];
    $options = array(
        PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES '.$dbconf['charset'],
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_PERSISTENT         => (bool)$dbconf['persist'],
    );
    parent::__construct($dsn, $dbconf['dbuser'], $dbconf['dbpass'],$options);
}
查看更多
神经病院院长
3楼-- · 2019-03-05 17:21

The reason being is PDO::__construct only creates the object upon successful connection. So when you call the parent constructor and it fails your object doesn't exist anymore. You should use self::myerror() to access the error function statically in this case.

查看更多
登录 后发表回答