I did some research and looked at documentation official . It does not seem possible to replace the PDOException
exception with a custom exception in some simple configuration.
However, I thought of some ways to get around the problem. Maybe some suits your case.
Capturing the exception globally
A simplistic and limited solution, if the exception can be handled globally, would be to use the set_exception_handler()
to catch exceptions not handled by try/catch
blocks.
The example below captures the exceptions and checks to see if it is of type PDOException
. If it is, it displays a message and allows the program to continue running. Otherwise it throws the exception.
function pdoExceptionHandler($e) {
if ($e instanceof PDOException) {
echo 'Erro PDO Capturado!';
} else {
throw $e;
}
}
set_exception_handler("pdoExceptionHandler");
See the working example on codepad .
This solution is limited because the handler function is only executed if the exception is not caught anywhere by a catch
.
Encapsulate the PDO
Another approach would be to not use PDO classes directly, but to create wrappers to abstract their functionality.
Encapsulation with inheritance
The first approach is to create classes that inherit from the original PDO and override the required methods, adding try/catch
and relaunching the custom exception. So you do the treatment once and reuse all the bank accesses you need.
In this SOEN question , I found an example similar to this, this is, a class abstracts the use of PDO. Note that the questioner states that there is a problem 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 true PDO. It would have an attribute that references the PDO and methods with the same signatures as the PDO, which delegates execution to the PDO, but handle the exception properly.
One technique that would help in this last approach to not 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 having to create each method dynamically and doing the processing in one point.
When a class has a __call($name, $arguments)
method, for example, and you call any method in that class, even though the method is not declared , PHP will execute __call
passing the name of the method called ( $name
) and the parameters in an array ( $arguments
). It's a very cool PHP feature!
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 that aims to make things easier the use of PDO. In addition to bringing in some useful methods, it has a method called setErrorCallbackFunction()
that might resolve your problem without you having to create your own solution.