I did some research and analyzed the documentation officer. It seems not possible to replace the exception PDOException
by a custom via some simple configuration.
However, I have thought of some ways around the problem. Maybe some of it will fit your case.
Capture the exception globally
A simplistic and limited solution, if the exception can be handled globally, would be to use the function set_exception_handler()
to capture exceptions not treated by blocks try/catch
.
The example below captures the exceptions and checks if it is of the type PDOException
. If it is, it displays a message and allows the program to continue running. Otherwise it relaunches the exception.
function pdoExceptionHandler($e) {
if ($e instanceof PDOException) {
echo 'Erro PDO Capturado!';
} else {
throw $e;
}
}
set_exception_handler("pdoExceptionHandler");
See the functional example on codepad.
This solution is limited because the function Handler is executed only if the exception is not captured anywhere by a catch
.
Encapsulate the PDO
Another approach would be not to use PDO classes directly, but to create Wrappers to abstract its functionalities.
Encapsulation with inheritance
The first approach is to create classes that inherit from the original PDO and overwrite the required methods by adding the treatment try/catch
and relaunching the custom exception. So you do the treatment once and reuse in all bank access you need.
In this question from the SOEN, I found an example similar to this, that is, a class abstract the use of PDO. Note that the questioner states that there is a problem when closing the connection with this class. Unfortunately I lack an environment to test and validate how it works. If you want to use it as a basis to develop yours, follow the code:
class Database extends PDO {
private $driver = "mysql";
private $host = "localhost";
private $dbname = "dbname";
private $user = "user";
private $pass = "pass";
private $connect = false;
private $error = "";
private $stmt = "";
public function __construct() {
$options = array(
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
);
try {
parent::__construct($this->driver.":host=".$this->host.";dbname=".$this->dbname, $this->user, $this->pass, $options);
} catch (PDOException $e) {
$this->error = $e->getMessage();
}
$this->connect = true;
}
public function run($statement, $bind = array()) {
try {
$this->stmt = $this->prepare($statement);
$this->stmt->execute($bind);
} catch (Exception $e) {
throw $e;
}
}
public function fetchAssoc() {
return $this->stmt->fetchAll(PDO::FETCH_ASSOC);
}
public function rowCount() {
return $this->stmt->rowCount();
}
public function getErrorMessage() {
return $this->error;
}
public function isOpen() {
return $this->connect;
}
public function close() {
//$this->connect = false;
}
public function __destruct() {
$this->connect = false;
}
}
Encapsulation with a proxy
Another approach would be to create a class that would function as a proxy for the real PDO. It would have an attribute that references the PDO and methods with the same signatures as the PDO, which delegate the execution to the PDO, but treat the exception properly.
A technique that would help in this last approach not to need to create all methods manually would be to use the triggers __call
and __callStatic
(see documentation). With them you can delegate normal and static calls to methods without creating each method, dynamically and doing the treatment in one point.
When a class has a method __call($name, $arguments)
, for example, and you call any method in that class, even if the method is not declared, PHP will run the __call
passing the name of the called method ($name
) and the parameters in an array ($arguments
). It’s a very nice feature of PHP!
I did a basic implementation
class MyPDO {
private $pdo = null;
function __construct($url, $user, $pw) {
$this->pdo = new PDO($url, $user, $pw);
}
public function __call($name, $arguments) {
try {
call_user_func_array(array($this->pdo, $name), $arguments);
} catch (PDOException $ex) {
throw new DataBaseException('database error');
}
}
}
See a functional example here.
Encapsulating with a library
I found a project called php-Pdo-wrapper-class which aims to facilitate a little the use of PDO. In addition to bringing some useful methods, it has a method called setErrorCallbackFunction()
that might solve your problem without you needing to create your own solution.
I don’t have a definitive answer yet, but looking at the sources of
PDO
and ofPEAR::raiseError
- in particular on the line$ec = $this->_error_class;
- I suspect it is possible yes... Tomorrow, if no one finds a solution, I will investigate again.– mgibsonbr