Created
November 23, 2015 21:57
-
-
Save nmcgann/128f4da51eeb83868638 to your computer and use it in GitHub Desktop.
PDO class to include timing and logging. Tested with mysql and mssql
This file contains hidden or 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 | |
/** | |
* dbpdo.php | |
* | |
* Wrapper class for PDO to handle connecting to different types of db (mssql and mysql). | |
* Also handles mssql on both windows and linux platforms by using sqlsrv and dblib pdo drivers. | |
* Adds a logging and timing facility for queries and prepared statements. | |
* A logging function can be passed to the constructor to capture all calls to the PDO routines. | |
* | |
* All normal PDO and PDOStatement functions can be used with no alterations. | |
* | |
* Constructor parameters: | |
* $params['db_type'] - currently 'mssql' or 'mysql' | |
* $params['db_host'] | |
* $params['db_port'] - (optional) | |
* $params['db_name'] - (optional) | |
* $params['db_username'] | |
* $params['db_password'] | |
* $params['commands'] - (optional) array of command strings to be run after connection made. | |
* | |
* After connection made isConnectionError() should be called to check if successful and then | |
* getConnectionError() gets the error message. All other errors raise an exception. | |
* | |
* The db logging routine passed should be able to accept a variable number of | |
* parameters to log each of which can be either scalar or arrays. | |
* | |
*/ | |
class Dbpdo { | |
protected $db = null; | |
protected $dbError = ''; | |
protected $dbLogHook = null; | |
// --------------------------------------------------------------------- // | |
public function __construct($params, $dbLogHook = null) { | |
$this->dbLogHook = $dbLogHook; | |
$this->openConnection($params); | |
} | |
// --------------------------------------------------------------------- // | |
protected function openConnection($params) { | |
$commands = array(); //special setup commands | |
//handle missing params (e.g. future proofing if sqlite used) | |
$dbtype = isset($params['db_type']) ? $params['db_type'] : 'mysql'; | |
$host = isset($params['db_host']) ? $params['db_host'] : ''; | |
$port = isset($params['db_port']) ? $params['db_port'] : ''; | |
$dbname = isset($params['db_name']) ? $params['db_name'] : ''; | |
$username = isset($params['db_username']) ? $params['db_username'] : ''; | |
$password = isset($params['db_password']) ? $params['db_password'] : ''; | |
//add any extra init commands | |
$commands = isset($params['commands']) ? array_merge($commands, $params['commands']) : $commands; | |
if($dbtype == 'mssql') { | |
$port = ($port != '') ? $port : 1433; //default port if not set | |
//windows servers have different drivers & dsn strings (Mac shows darwin, so can't just look for "win") | |
if(strncasecmp(PHP_OS, 'WIN', 3) == 0) { | |
$dsn = "sqlsrv:server=$host,$port". (($dbname != "") ? ";database=$dbname" : ""); | |
} else { | |
//linux etc. | |
$dsn = "dblib:host=$host:$port".(($dbname != "") ? ";dbname=$dbname" : ""); | |
} | |
$commands[] = "SET QUOTED_IDENTIFIER ON"; //should be unnecessary, but safest to be explicit | |
} else { | |
//assumed mysql | |
$port = ($port != '') ? $port : 3306; | |
$charset = isset($params['db_charset']) ? ';charset=' . $params['db_charset'] : ';charset=utf8'; | |
$dsn = "mysql:host=$host;port=$port". (($dbname != "") ? ";dbname=$dbname" : "") . $charset; | |
} | |
//open up (suppressing separate messages) | |
try { | |
$this->db = @new PDO($dsn, $username, $password); | |
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); | |
if($dbtype != 'mssql') { | |
$this->db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); | |
} | |
//run any special set up commands | |
foreach($commands as $c) { | |
$this->db->exec($c); | |
} | |
} catch(PDOException $e) { | |
$this->dbError = $e->getMessage(); | |
$this->db = null; | |
//call logging hook if present | |
if(is_callable($this->dbLogHook)) { | |
$fn = $this->dbLogHook; | |
$fn('Error connecting to database', $this->dbError); | |
} | |
//exit($this->dbError); | |
} | |
} | |
// --------------------------------------------------------------------- // | |
public function isConnectionError () { | |
return is_null($this->db); | |
} | |
// --------------------------------------------------------------------- // | |
public function getConnectionError () { | |
return $this->dbError; | |
} | |
// --------------------------------------------------------------------- // | |
public function query(){ | |
$args = func_get_args(); | |
$start = microtime(true); | |
$result = call_user_func_array(array($this->db, 'query'), $args); | |
$time = microtime(true) - $start; | |
//call logging hook if present | |
if(is_callable($this->dbLogHook)) { | |
$fn = $this->dbLogHook; | |
$fn('PDO->query took ' . round($time * 1000, 3) . 'ms ', $args); | |
} | |
return $result; | |
} | |
// --------------------------------------------------------------------- // | |
public function exec($statement){ | |
$start = microtime(true); | |
$result = $this->db->exec($statement); | |
$time = microtime(true) - $start; | |
//call logging hook if present | |
if(is_callable($this->dbLogHook)) { | |
$fn = $this->dbLogHook; | |
$fn('PDO->exec took ' . round($time * 1000, 3) . 'ms ', $statement); | |
} | |
return $result; | |
} | |
// --------------------------------------------------------------------- // | |
//call standard PDO methods | |
public function __call($name, $args) { | |
//call logging hook if present | |
if(is_callable($this->dbLogHook)) { | |
$fn = $this->dbLogHook; | |
$fn($name, $args); | |
} | |
$result = call_user_func_array(array($this->db, $name), $args); | |
//substitute logged PDOStatement if a logger is present | |
if(is_object($result) && get_class($result) === 'PDOStatement' && is_callable($this->dbLogHook)) { | |
return new LoggedPDOStatement($result, $this->dbLogHook); | |
} | |
return $result; | |
} | |
} //eoc | |
/** | |
* LoggedPDOStatement is returned instead of PDOStatement when logging is active. | |
* This allows the prepared statement execution time to be logged. | |
* | |
*/ | |
class LoggedPDOStatement { | |
private $statement; | |
private $dbLogHook = null; | |
// --------------------------------------------------------------------- // | |
public function __construct(PDOStatement $statement, $dbLogHook = null) { | |
$this->statement = $statement; | |
$this->dbLogHook = $dbLogHook; | |
} | |
// --------------------------------------------------------------------- // | |
public function execute($args = null) { | |
$start = microtime(true); | |
$result = $this->statement->execute($args); | |
$time = microtime(true) - $start; | |
//call logging hook if present | |
if(is_callable($this->dbLogHook)) { | |
$fn = $this->dbLogHook; | |
$fn('PDOStatement->execute took ' . round($time * 1000, 3) . 'ms ', is_null($args) ? '(no parameters)' : $args); | |
} | |
return $result; | |
} | |
// --------------------------------------------------------------------- // | |
//functions with pass-by-reference parameter(s) need special treatment | |
public function bindColumn($column, &$param, $type = null, $maxlen = null, $driverdata = null) { | |
//call logging hook if present | |
if(is_callable($this->dbLogHook)) { | |
$fn = $this->dbLogHook; | |
$fn('PDOStatement->bindColumn', $column, $param, $type, $maxlen, $driverdata); | |
} | |
return $this->statement->bindColumn($column, $param, $type, $maxlen, $driverdata); | |
} | |
// --------------------------------------------------------------------- // | |
public function bindParam($parameter, &$variable, $data_type = PDO::PARAM_STR, $length = null, $driver_options = null) { | |
//call logging hook if present | |
if(is_callable($this->dbLogHook)) { | |
$fn = $this->dbLogHook; | |
$fn('PDOStatement->bindParam', $parameter, $variable, $data_type, $length, $driver_options); | |
} | |
return $this->statement->bindParam($parameter, $variable, $data_type, $length, $driver_options); | |
} | |
// --------------------------------------------------------------------- // | |
public function bindValue($parameter, $value, $data_type = PDO::PARAM_STR) { | |
//call logging hook if present | |
if(is_callable($this->dbLogHook)) { | |
$fn = $this->dbLogHook; | |
$fn('PDOStatement->bindValue', $parameter, $value, $data_type); | |
} | |
return $this->statement->bindValue($parameter, $value, $data_type); | |
} | |
// --------------------------------------------------------------------- // | |
//all other functions go direct to PDOStatement object | |
public function __call($name, $param) { | |
//call logging hook if present | |
if(is_callable($this->dbLogHook)) { | |
$fn = $this->dbLogHook; | |
$fn($name, $param); | |
} | |
return call_user_func_array(array($this->statement, $name), $param); | |
} | |
} //eoc | |
/* end */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment