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?

回答1:

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.



回答2:

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


标签: php class pdo