Skip to content

Instantly share code, notes, and snippets.

@roncemer
Last active June 13, 2019 22:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save roncemer/d24a25df0c15623fc24c482d8e74c8be to your computer and use it in GitHub Desktop.
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
<?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