Last active
June 13, 2019 22:08
-
-
Save roncemer/d24a25df0c15623fc24c482d8e74c8be to your computer and use it in GitHub Desktop.
PHP PDO class with lazy connect and fail-over to alternate database servers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class FailoverPDO extends PDO | |
{ | |
protected $dsns, $failoverDSNIdx, $username, $passwd, $options, $connectCallback; | |
public $logConnectFailures = true; | |
protected $attrs = []; | |
protected $connectAttempted = false; | |
protected $pdo = null; | |
public function __construct($primaryDSNs, $failoverDSNs, $username = '', $passwd = '', $options = [], $connectCallback = null) | |
{ | |
$primaryDSNs = (is_array($primaryDSNs) && (!empty($primaryDSNs))) ? | |
array_unique($primaryDSNs) : []; | |
$failoverDSNs = (is_array($failoverDSNs) && (!empty($failoverDSNs))) ? | |
array_diff(array_unique($failoverDSNs), $primaryDSNs) : []; | |
$this->failoverDSNIdx = count($primaryDSNs); | |
$this->dsns = array_merge($primaryDSNs, $failoverDSNs); | |
$this->username = $username; | |
$this->passwd = $passwd; | |
if (array_key_exists('logConnectFailures', $options)) { | |
$this->logConnectFailures = (boolean)$options['logConnectFailures']; | |
unset($options['logConnectFailures']); | |
} | |
$this->options = $options; | |
$this->connectCallback = $connectCallback; | |
} // __construct() | |
public function beginTransaction() | |
{ | |
if ($this->pdo === null) { | |
$this->lazyConnect(); | |
} | |
return $this->pdo->beginTransaction(); | |
} // beginTransaction() | |
public function commit() | |
{ | |
if ($this->pdo === null) { | |
$this->lazyConnect(); | |
} | |
return $this->pdo->commit(); | |
} // commit() | |
public function errorCode() | |
{ | |
if ($this->pdo === null) { | |
$this->lazyConnect(); | |
} | |
return $this->pdo->errorCode(); | |
} // errorCode() | |
public function errorInfo() | |
{ | |
if ($this->pdo === null) { | |
$this->lazyConnect(); | |
} | |
return $this->pdo->errorInfo(); | |
} // errorInfo() | |
public function exec($statement) | |
{ | |
if ($this->pdo === null) { | |
$this->lazyConnect(); | |
} | |
return $this->pdo->exec($statement); | |
} // exec() | |
public function getAttribute($attribute) | |
{ | |
if ($this->pdo === null) { | |
// If we're getting an attribute which we previously set, return that; | |
// otherwise, initialize the backing PDO instance and get the attribute from it. | |
if (array_key_exists($args[0], $this->attrs)) { | |
return $this->attrs[$args[0]]; | |
} | |
$this->lazyConnect(); | |
} | |
return $this->pdo->getAttribute($attribute); | |
} // getAttribute() | |
public function inTransaction() | |
{ | |
if ($this->pdo === null) { | |
$this->lazyConnect(); | |
} | |
return $this->pdo->inTransaction(); | |
} // inTransaction() | |
public function lastInsertId($name = null) | |
{ | |
if ($this->pdo === null) { | |
$this->lazyConnect(); | |
} | |
return $this->pdo->lastInsertId($name); | |
} // lastInsertId() | |
public function prepare($statement, $driver_options = []) | |
{ | |
if ($this->pdo === null) { | |
$this->lazyConnect(); | |
} | |
return $this->pdo->prepare($statement, $driver_options); | |
} // prepare() | |
public function query(string $statement) | |
{ | |
if ($this->pdo === null) { | |
$this->lazyConnect(); | |
} | |
return $this->pdo->query($statement); | |
} // query() | |
public function quote($string, $parameter_type = PDO::PARAM_STR) | |
{ | |
if ($this->pdo === null) { | |
$this->lazyConnect(); | |
} | |
return $this->pdo->quote($string, $parameter_type); | |
} // quote() | |
public function rollBack() | |
{ | |
if ($this->pdo === null) { | |
$this->lazyConnect(); | |
} | |
return $this->pdo->rollBack(); | |
} // rollBack() | |
public function setAttribute($attribute, $value) | |
{ | |
if ($this->pdo === null) { | |
$this->attrs[$attribute] = $value; | |
return true; | |
} | |
return $this->pdo->setAttribute($attribute, $value); | |
} // setAttribute() | |
protected function lazyConnect() | |
{ | |
if ($this->connectAttempted) { | |
throw new PDOException('Not connected'); | |
} | |
$this->connectAttempted = true; | |
for ($i = 0, $n = count($this->dsns); $i < $n; $i++) { | |
try { | |
$this->pdo = new PDO($this->dsns[$i], $this->username, $this->passwd, $this->options); | |
foreach ($this->attrs as $attribute=>$value) { | |
$this->pdo->setAttribute($attribute, $value); | |
} | |
if (is_callable($this->connectCallback)) { | |
call_user_func_array($this->connectCallback, [$this, $this->dsns[$i], $i >= $this->failoverDSNIdx]); | |
} | |
return; | |
} catch (PDOException $ex) { | |
if (($i+1) >= $n) { | |
throw $ex; | |
} else { | |
if ($this->logConnectFailures) { | |
error_log(sprintf('Connection to dsn %s failed; trying next dsn', $this->dsns[$i])); | |
} | |
} | |
} | |
} | |
} // lazyConnect() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment