PDO Database class not stopping at catching exception - php

I have the following code within a PDO database class
/**
* Class DB
*/
class DB{
/**
* #var DB The one and only instance of this class;
*/
private static $theOneAndOnly = null;
/**
* #var array
*/
private static $transactionalOptions = array( PDO::ATTR_AUTOCOMMIT => false, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC );
/**
* #var array
*/
private static $nonTransactionalOptions = array( PDO::ATTR_AUTOCOMMIT => true, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC );
/**
* #var PDO
*/
private $transactionalDatabase = null;
/**
* #var PDO
*/
private $nonTransactionalDatabase = null;
/**
* #var bool
*/
private $isConnected = false;
/**
* Initializes the connections to the database. One connection for transaction based operations and one connection
* for non-transactional operations;
*/
private function __construct(){
if($this->isConnected() !== true){
//connect
if($this->connect() !== true){
//connection failed
exit( 'An internal error occurred. Please contact Keyfort support:' );
}
}
}
/**
* #return bool
*/
public function isConnected(){
return $this->isConnected;
}
/**
* #return bool
*/
public function connect(){
try{
$this->transactionalDatabase = new PDO(Config::DB_TYPE . ':host=' . Config::DB_HOST . ';dbname=' . Config::$DB_NAME, Config::$DB_USER, Config::$DB_PASS, self::$transactionalOptions);
$this->nonTransactionalDatabase = new PDO(Config::DB_TYPE . ':host=' . Config::DB_HOST . ';dbname=' . Config::$DB_NAME, Config::$DB_USER, Config::$DB_PASS, self::$nonTransactionalOptions);
$this->isConnected = true;
return true;
} catch(PDOException $exception){
Log::error('Initializing the database connections failed:' . $exception->getTraceAsString());
die();
//return false;
}
}
/**
* #return DB
*/
public static function &getInstance(){
if(self::$theOneAndOnly === null){
self::$theOneAndOnly = new self();
}
return self::$theOneAndOnly;
}
public static function ParamMultiple($key){
return self::Param($key) . ', ';
}
public static function Param($key){
return ':' . $key;
}
/**
* Close all connections;
*/
public function __destruct(){
$this->disconnect();
}
/**
* #return void
*/
public function disconnect(){
$this->transactionalDatabase = null;
$this->nonTransactionalDatabase = null;
$this->isConnected = false;
}
/**
* #return PDO
*/
public function &getTransactional(){
if($this->isConnected() !== true){
$this->connect();
}
return $this->transactionalDatabase;
}
/**
* #return PDO
*/
public function &getBasic(){
if($this->isConnected() !== true){
$this->connect();
}
return $this->nonTransactionalDatabase;
}
}
It gets called via DB::getInstance();
The first time it gets called, it does not "die" if it errors.
I eventually get
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 32 bytes) in C:\path\to\class\db.php on line 64
Line 64 is the $this->transactionalDatabase line.
It does log the exception in my error log (as in the catch).
I'm drawing a blank as to why its not "die"ing, I've tried alot of things, and I'm wondering if it could be starting 2 PDOs in the try?
[edit]
I'm running through the code with the wrong database user password currently. So I know what the error is caused by (it works ok when i put the correct password in), I just don't understand why it isn't processing the die() in the catch.
Use Fragment:
public static function GetByUsername($username){
$db = DB::getInstance();
$dbh = $db->getBasic();
$sql = 'SELECT * FROM ' . self::TABLE_NAME . ' WHERE ' . self::KEY_USERNAME . ' = ' . DB::Param(self::KEY_USERNAME);
$statement = $dbh->prepare($sql);
$statement->bindValue(DB::Param(self::KEY_USERNAME), $username);
if($statement->execute() === true){
$rawUser = $statement->fetch();
if($rawUser === null){
return null;
} else {
return self::CreateFromSelectResult($rawUser);
}
} else {
Log::error("Fetching user by username failed:" . print_r($dbh->errorInfo(), true));
return null;
}
}

Try using either transactionalDatabase or nonTransactionalDatabase, it should solve the problem.

Make sure your /tmp folder has space to cache queries.

The issue was within "Log::error();"
Log:error() also tries to use the database.
So the issue was an infinite loop that started before the die() line was reached.

Related

Adding Authentication to SOAP web services using Laminas-soap and php

Hello fellow travellers,
I am trying to learn how to create SOAP Web services end point in PHP. I have found Laminas-soap with its elegant solution. However when trying to add authentication to it although it works when adding creditials to SoapHeaders it goes through, the problem is even without SoapHeaders credentials it still goes through. Can anybody help me with this problem? Here is my Server Code:
Update: Should I just put authentication on every call to not put state on the server?
<?php
// api.php
require_once __DIR__ . '/vendor/autoload.php';
require_once '../classes/DBConnection.php';
class Server
{
private $conn;
/**
* authenticate
*
* #param string $username
* #param string $password
* #return boolean
*/
public static function authenticate($username, $password)
{
if($username == "Kaloy" && $password == 'password') return true;
else throw new SOAPFault("Wrong user/pass combination", 401);
}
public function __construct($conn)
{
$this->conn = $conn;
}
/**
* Say hello.
*
* #param string $firstName
* #return string $greetings
*/
public function sayHello($firstName)
{
return 'Hello ' . $firstName;
}
/**
* get products
*
* #param string $category
* #param string $category2
* #param string $category3
* #param string $category4
* #return Array $products
*/
public function getProd($category, $category2, $category3, $category4) {
if ($category == "books") {
// return join(",", array(
// "The WordPress Anthology",
// "PHP Master: Write Cutting Edge Code",
// "Build Your Own Website the Right Way"));
return array(
"The WordPress Anthology",
"PHP Master: Write Cutting Edge Code",
"Build Your Own Website the Right Way");
}
else {
return array("No products listed under that category");
}
}
/**
* getData
*
* #param string $id
* #return Object
*/
public function getData($id)
{
$result = [];
if (is_null($id)) return $result;
$qry = "SELECT * FROM test_table";
return $this->conn->query($qry)->fetchAll(PDO::FETCH_ASSOC);
}
}
$serverUrl = "http://localhost/laminas-soap/api.php";
$options = [
'uri' => $serverUrl,
];
$server = new \Laminas\Soap\Server(null, $options);
if (isset($_GET['wsdl'])) {
$soapAutoDiscover = new \Laminas\Soap\AutoDiscover(new \Laminas\Soap\Wsdl\ComplexTypeStrategy\ArrayOfTypeSequence());
$soapAutoDiscover->setBindingStyle(array('style' => 'document'));
$soapAutoDiscover->setOperationBodyStyle(array('use' => 'literal'));
$soapAutoDiscover->setClass('Server');
$soapAutoDiscover->setUri($serverUrl);
header("Content-Type: text/xml");
echo $soapAutoDiscover->generate()->toXml();
} else {
$soap = new \Laminas\Soap\Server($serverUrl . '?wsdl');
$soap->setObject(new \Laminas\Soap\Server\DocumentLiteralWrapper(new Server($conn)));
$soap->handle();
}

PHP:How to take backup of mysql database according to the given time period (eg :last6 months)

This code is used to backup mysql database. I want to modify the code given below as it performs taking backup according to the given time period .expecting your help.
Class DBBackup {
/**
*
* The host you will connect
* #var String
*/
private $host;
/**
*
* The driver you will use to connect
* #var String
*/
private $driver;
/**
*
* The user you will use to connect to a database
* #var String
*/
private $user;
/**
*
* The password you will use to connect to a database
* #var String
*/
private $password;
/**
*
* The database you will use to connect
* #var String
*/
private $dbName;
/**
*
* String to connect to the database using PDO
* #var String
*/
private $dsn;
/**
*
* Array with the tables of the database
* #var Array
*/
private $tables = array();
/**
*
* Hold the connection
* #var ObjectConnection
*/
private $handler;
/**
*
* Array to hold the errors
* #var Array
*/
private $error = array();
/**
*
* The result string. String with all queries
* #var String
*/
private $final;
/**
*
* The main function
* #method DBBackup
* #uses Constructor
* #param Array $args{host, driver, user, password, database}
* #example $db = new DBBackup(array('host'=>'my_host', 'driver'=>'bd_type(mysql)', 'user'=>'db_user', 'password'=>'db_password', 'database'=>'db_name'));
*/
public function DBBackup($args){
if(!$args['host']) $this->error[] = 'Parameter host missing';
if(!$args['user']) $this->error[] = 'Parameter user missing';
if(!isset($args['password'])) $this->error[] = 'Parameter password missing';
if(!$args['database']) $this->error[] = 'Parameter database missing';
if(!$args['driver']) $this->error[] = 'Parameter driver missing';
if(count($this->error)>0){
return;
}
$this->host = $args['host'];
$this->driver = $args['driver'];
$this->user = $args['user'];
$this->password = $args['password'];
$this->dbName = $args['database'];
$this->final = 'CREATE DATABASE ' . $this->dbName.";\n\n";
if($this->host=='localhost'){
// We have a little issue in unix systems when you set the host as localhost
$this->host = '127.0.0.1';
}
$this->dsn = $this->driver.':host='.$this->host.';dbname='.$this->dbName;
$this->connect();
$this->getTables();
$this->generate();
}
/**
*
* Call this function to get the database backup
* #example DBBackup::backup();
*/
public function backup(){
//return $this->final;
if(count($this->error)>0){
return array('error'=>true, 'msg'=>$this->error);
}
return array('error'=>false, 'msg'=>$this->final);
}
/**
*
* Generate backup string
* #uses Private use
*/
private function generate(){
foreach ($this->tables as $tbl) {
$this->final .= '--CREATING TABLE '.$tbl['name']."\n";
$this->final .= $tbl['create'] . ";\n\n";
$this->final .= '--INSERTING DATA INTO '.$tbl['name']."\n";
$this->final .= $tbl['data']."\n\n\n";
}
$this->final .= '-- THE END'."\n\n";
}
/**
*
* Connect to a database
* #uses Private use
*/
private function connect(){
try {
$this->handler = new PDO($this->dsn, $this->user, $this->password);
} catch (PDOException $e) {
$this->handler = null;
$this->error[] = $e->getMessage();
return false;
}
}
/**
*
* Get the list of tables
* #uses Private use
*/
private function getTables(){
try {
$stmt = $this->handler->query('SHOW TABLES');
$tbs = $stmt->fetchAll();
$i=0;
foreach($tbs as $table){
$this->tables[$i]['name'] = $table[0];
$this->tables[$i]['create'] = $this->getColumns($table[0]);
$this->tables[$i]['data'] = $this->getData($table[0]);
$i++;
}
unset($stmt);
unset($tbs);
unset($i);
return true;
} catch (PDOException $e) {
$this->handler = null;
$this->error[] = $e->getMessage();
return false;
}
}
/**
*
* Get the list of Columns
* #uses Private use
*/
private function getColumns($tableName){
try {
$stmt = $this->handler->query('SHOW CREATE TABLE '.$tableName);
$q = $stmt->fetchAll();
$q[0][1] = preg_replace("/AUTO_INCREMENT=[\w]*./", '', $q[0][1]);
return $q[0][1];
} catch (PDOException $e){
$this->handler = null;
$this->error[] = $e->getMessage();
return false;
}
}
/**
*
* Get the insert data of tables
* #uses Private use
*/
private function getData($tableName){
try {
$stmt = $this->handler->query('SELECT * FROM '.$tableName);
$q = $stmt->fetchAll(PDO::FETCH_NUM);
$data = '';
foreach ($q as $pieces){
foreach($pieces as &$value){
$value = htmlentities(addslashes($value));
}
$data .= 'INSERT INTO '. $tableName .' VALUES (\'' . implode('\',\'', $pieces) . '\');'."\n";
}
return $data;
} catch (PDOException $e){
$this->handler = null;
$this->error[] = $e->getMessage();
return false;
}
}
}
?>
Use crontab (chrono table) to perfoms it :
just must create a simple php file what use your class.
define the time period on the server side (using crontab -e command) and call the file
Note: you must got a ssh access to the server.
More information here.

PHPUnit database testing and Travis CI: Can't truncate table

I'm writing PHPUnit tests to test MySQL database filling. My tests work fine locally, but are failing on Travis CI with the following error:
PHPUnit_Extensions_Database_Operation_Exception: COMPOSITE[TRUNCATE] operation failed on query:
TRUNCATE `simple_table`
using args: Array
[SQLSTATE[42S02]: Base table or view not found: 1146 Table 'test.simple_table' doesn't exist]
I have a DatabaseTestCase parent class and a FillCommandTest testing class.
DatabaseTestCase
class DatabaseTestCase extends PHPUnit_Extensions_Database_TestCase
{
private static $pdo = null;
private $connection = null;
/**
* Construct.
*/
public function __construct()
{
$env = new Environment();
$this->dsn = "mysql:dbname=". $env->get('DB_DATABASE', 'test') . ";host=" . $env->get('DB_HOST', '127.0.0.1');
$this->username = $env->get('DB_USERNAME', 'travis');
$this->password = $env->get('DB_PASSWORD', '');
$this->db_name = $env->get('DB_DATABASE', 'test');
}
/**
* Get database connection.
*
* #return PHPUnit_Extensions_Database_DB_DefaultDatabaseConnection
*/
final public function getConnection()
{
if ($this->connection === null) {
if (self::$pdo == null) {
self::$pdo = new PDO($this->dsn, $this->username, $this->password);
}
$this->connection = $this->createDefaultDBConnection(self::$pdo, $this->db_name);
}
return $this->connection;
}
/**
* Get XML dataset.
*
* #param string $file
* #return string
*/
public function getDataSet($file = 'empty.xml')
{
$file = 'tests/datasets/' . $file;
return $this->createXmlDataSet($file);
}
/**
* Set up the test database table
*
* #param PHPUnit_Extensions_Database_DB_DefaultDatabaseConnection $connection
*/
protected function setUpTable($connection)
{
$pdo = $connection->getConnection();
$sql = "CREATE TABLE IF NOT EXISTS simple_table (
id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
email VARCHAR(50) NOT NULL,
address VARCHAR(100)
)";
$pdo->exec($sql);
}
}
FillCommandTest
class FillCommandTest extends DatabaseTestCase
{
protected $app;
protected $command;
protected $command_tester;
/**
*
*/
public function setUp()
{
$this->app = new Application();
$this->app->add(new FillCommand());
$this->command = $this->app->find('fill');
$this->command_tester = new CommandTester($this->command);
parent::setUp();
$connection = $this->getConnection();
$this->setUpTable($connection);
}
/**
*
*/
public function test_parse_and_fill_simple_table()
{
copy(getcwd() . '/tests/files/FillSimpleTable.php', getcwd() . '/src/Fillers/FillSimpleTable.php');
copy(getcwd() . '/tests/files/simple.txt', getcwd() . '/src/Files/simple.txt');
$this->command_tester->execute(array(
'command' => $this->command->getName(),
'name' => 'simple_table'
));
$actual = $this->getConnection()->createQueryTable('simple_table', 'SELECT * FROM simple_table');
$expected = $this->getDataSet('simple_table.xml')->getTable('simple_table');
$this->assertTablesEqual($expected, $actual);
unlink(getcwd() . '/src/Fillers/FillSimpleTable.php');
unlink(getcwd() . '/src/Files/simple.txt');
}
}
What am I doing wrong?
By the looks of it, it seems your code is referring to a database called 'test'.
But I am assuming since you are deploying, your database name should be different. Make sure your .env DB_DATABASE variable reflects the correct one on your production server.

Query in a class with variable

I have created a timeclock system for a website admin area I am working on. But I want to use a class to handle the code in a better way so I am starting over. So far I have 2 classes. One to handle the database connection and the queries to the database through PDO.
When starting the class for the timeclock (Which I am having to build from scratch) I am getting close because I am no longer receiving errors when I load the page. But the results of the query are not right as I should be returning "true" instead of NULL for a record coming from the database. Can someone please help me understand what I am doing wrong.
My Database class is like so(From GitHub)...
/**
* DB - A simple database class
*
* #author Author: Vivek Wicky Aswal. (https://twitter.com/#!/VivekWickyAswal)
* #git https://github.com/indieteq/PHP-MySQL-PDO-Database-Class
* #version 0.2ab
*
*/
require("Log.class.php");
class DB
{
# #object, The PDO object
private $pdo;
# #object, PDO statement object
private $sQuery;
# #array, The database settings
private $settings;
# #bool , Connected to the database
private $bConnected = false;
# #object, Object for logging exceptions
private $log;
# #array, The parameters of the SQL query
private $parameters;
/**
* Default Constructor
*
* 1. Instantiate Log class.
* 2. Connect to database.
* 3. Creates the parameter array.
*/
public function __construct()
{
$this->log = new Log();
$this->Connect();
$this->parameters = array();
}
/**
* This method makes connection to the database.
*
* 1. Reads the database settings from a ini file.
* 2. Puts the ini content into the settings array.
* 3. Tries to connect to the database.
* 4. If connection failed, exception is displayed and a log file gets created.
*/
private function Connect()
{
$host = 'localhost';
$username = 'root';
$password = '';
$dbname = 'acro_1986';
//$this->settings = parse_ini_file("settings.ini.php");
$dsn = 'mysql:dbname='.$dbname.';host='.$host.'';
try
{
# Read settings from INI file, set UTF8
$this->pdo = new PDO($dsn, $username, $password, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
# We can now log any exceptions on Fatal error.
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
# Disable emulation of prepared statements, use REAL prepared statements instead.
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
# Connection succeeded, set the boolean to true.
$this->bConnected = true;
}
catch (PDOException $e)
{
# Write into log
echo $this->ExceptionLog($e->getMessage());
die();
}
}
/*
* You can use this little method if you want to close the PDO connection
*
*/
public function CloseConnection()
{
# Set the PDO object to null to close the connection
# http://www.php.net/manual/en/pdo.connections.php
$this->pdo = null;
}
/**
* Every method which needs to execute a SQL query uses this method.
*
* 1. If not connected, connect to the database.
* 2. Prepare Query.
* 3. Parameterize Query.
* 4. Execute Query.
* 5. On exception : Write Exception into the log + SQL query.
* 6. Reset the Parameters.
*/
private function Init($query,$parameters = "")
{
# Connect to database
if(!$this->bConnected) { $this->Connect(); }
try {
# Prepare query
$this->sQuery = $this->pdo->prepare($query);
# Add parameters to the parameter array
$this->bindMore($parameters);
# Bind parameters
if(!empty($this->parameters)) {
foreach($this->parameters as $param)
{
$parameters = explode("\x7F",$param);
$this->sQuery->bindParam($parameters[0],$parameters[1]);
}
}
# Execute SQL
$this->succes = $this->sQuery->execute();
}
catch(PDOException $e)
{
# Write into log and display Exception
echo $this->ExceptionLog($e->getMessage(), $query );
die();
}
# Reset the parameters
$this->parameters = array();
}
/**
* #void
*
* Add the parameter to the parameter array
* #param string $para
* #param string $value
*/
public function bind($para, $value)
{
$this->parameters[sizeof($this->parameters)] = ":" . $para . "\x7F" . utf8_encode($value);
}
/**
* #void
*
* Add more parameters to the parameter array
* #param array $parray
*/
public function bindMore($parray)
{
if(empty($this->parameters) && is_array($parray)) {
$columns = array_keys($parray);
foreach($columns as $i => &$column) {
$this->bind($column, $parray[$column]);
}
}
}
/**
* If the SQL query contains a SELECT or SHOW statement it returns an array containing all of the result set row
* If the SQL statement is a DELETE, INSERT, or UPDATE statement it returns the number of affected rows
*
* #param string $query
* #param array $params
* #param int $fetchmode
* #return mixed
*/
public function query($query,$params = null, $fetchmode = PDO::FETCH_ASSOC)
{
$query = trim($query);
$this->Init($query,$params);
$rawStatement = explode(" ", $query);
# Which SQL statement is used
$statement = strtolower($rawStatement[0]);
if ($statement === 'select' || $statement === 'show') {
return $this->sQuery->fetchAll($fetchmode);
}
elseif ( $statement === 'insert' || $statement === 'update' || $statement === 'delete' ) {
return $this->sQuery->rowCount();
}
else {
return NULL;
}
}
/**
* Returns the last inserted id.
* #return string
*/
public function lastInsertId() {
return $this->pdo->lastInsertId();
}
/**
* Returns an array which represents a column from the result set
*
* #param string $query
* #param array $params
* #return array
*/
public function column($query,$params = null)
{
$this->Init($query,$params);
$Columns = $this->sQuery->fetchAll(PDO::FETCH_NUM);
$column = null;
foreach($Columns as $cells) {
$column[] = $cells[0];
}
return $column;
}
/**
* Returns an array which represents a row from the result set
*
* #param string $query
* #param array $params
* #param int $fetchmode
* #return array
*/
public function row($query,$params = null,$fetchmode = PDO::FETCH_ASSOC)
{
$this->Init($query,$params);
return $this->sQuery->fetch($fetchmode);
}
/**
* Returns the value of one single field/column
*
* #param string $query
* #param array $params
* #return string
*/
public function single($query,$params = null)
{
$this->Init($query,$params);
return $this->sQuery->fetchColumn();
}
/**
* Writes the log and returns the exception
*
* #param string $message
* #param string $sql
* #return string
*/
private function ExceptionLog($message , $sql = "")
{
$exception = 'Unhandled Exception. <br />';
$exception .= $message;
$exception .= "<br /> You can find the error back in the log.";
if(!empty($sql)) {
# Add the Raw SQL to the Log
$message .= "\r\nRaw SQL : " . $sql;
}
# Write into log
$this->log->write($message);
return $exception;
}
}
My Timeclock class...
class Timeclock {
public $user_id;
public function __construct($user_id) {
$this->user_id = $user_id ;
$this->db = new Db();
//$this->clocked_in = is_user_clocked_in($user_id);
}
public function is_user_clocked_in(){
$result = $this->db->query("SELECT * FROM timeclock WHERE user_id = :user_id AND time_out IS NULL", array("user_id"=>$this->user_id));
if ( count ( $result ) > 0 ){
return $result[0];
}else{
return null;
}
}
}
And I am calling it like so...
if (isset($_SESSION['admin'])) {
$_user_id = $_SESSION['admin'][0]['user_id'];
// calls action and determines case
if (isset($_POST['action'])) {
$action = $_POST['action'];
} else if (isset($_GET['action'])) {
$action = $_GET['action'];
} else {
$action = 'home';
}
$action = strtolower($action);
switch ($action) {
case 'home':
$timeclock = new Timeclock($_user_id);
$user = new Timeclock($timeclock->user_id);
$clocked_in = $user->is_user_clocked_in();
include ('dashboard.php');
break;
}
}
Also, is it possible to have every function in the class (Once its done) run one after the other and fill in the declared variables at the top (Once I have added them of course) so I can just call the class and have it run through once? Or will I have to call each function individually on demand?
Thanks for the attempt to help #Ohgodwhy. $clocked_in was returning an array because I asked it to select all columns in the table. So when there was a result, it was an array. I changed the return of the function to return true instead of $result[0] because I only need to know if the user is logged in. I could have probably just changed the query to select that column as well. After doing that, it worked great until I provided a value for the table field (Making the user clocked_in). I then got a Undefined offset:0 error because I was trying to call the value of $result[0] when there was no array indexed because the query obviously returns array(0); I just changed the count to check to see if $result exists.
updated code is as follows in case someone comes across this
Timeclock Class
class Timeclock {
public $user_id;
public function __construct($user_id) {
$this->user_id = $user_id ;
$this->db = new Db();
//$this->clocked_in = is_user_clocked_in($user_id);
}
public function is_user_clocked_in(){
$result = $this->db->query("SELECT * FROM timeclock WHERE user_id = :user_id AND time_out IS NULL", array("user_id"=>$this->user_id));
if ( count ($result) > 0 ){
return true;
}else{
return null;
}
}
}

How can I make a singleton wrapper for PDO?

How can I make a singleton of the PDO extention? Extending doesn't work, because I get a fatal error when I try it ...
You don't need a Singleton.
But to answer this nevertheless:
You cannot turn a public visibility to a stricter visibility. So PDO cannot have the constructor's visibility changed to anything but public. So you need to wrap the PDO instance into a Singleton:
class MyPdo
{
/**
* #var MyPdo
*/
protected static $_instance;
/**
* #var Pdo
*/
protected $_pdo;
/**
* Creates instance and returns it on subsequent calls
*
* #throws InvalidArgumentException
* #param array $options PDO connection data
* #returns MyPdo
*/
public static function getInstance(array $options = NULL)
{
if(self::$_instance === NULL) {
if($options === NULL) {
throw new InvalidArgumentException(
'You must supply connection options on first run');
}
// call constructor with given options and assign instance
self::$_instance = new self(
$options['dsn'],
$options['user'],
$options['password'],
$options['driver_options']
);
}
return self::$_instance;
}
/**
* Creates new MyPdo wrapping a PDO instance
*
* #throws PDOException
* #param String $dsn
* #param String $user
* #param String $password
* #param Array $driver_options
* #return void
*/
private function __construct($dsn, $user, $password, $driver_options)
{
try {
$this->_pdo = new PDO($dsn, $user, $password, $driver_options);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
}
/**
* Singletons may not be cloned
*/
private function __clone() {}
/**
* Delegate every get to PDO instance
*
* #param String $name
* #return Mixed
*/
public function __get($name)
{
return $this->_pdo->$name;
}
/**
* Delegate every set to PDO instance
*
* #param String $name
* #param Mixed $val
* #return Mixed
*/
public function __set($name, $val)
{
return $this->_pdo->$name = $val;
}
/**
* Delegate every method call to PDO instance
*
* #param String $method
* #param Array $args
* #return Mixed
*/
public function __call($method, $args) {
return call_user_func_array(array($this->_pdo, $method), $args);
}
}
You'd use it like this:
$db = MyPdo::getInstance(array(
'dsn'=>'mysql:dbname=mysql;host=127.0.0.1',
'user' => 'root',
'password' => 'minnymickydaisydonaldplutogoofysanfrancisco',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"
)));
$version = $db->query( 'SELECT version();' );
echo $version->fetchColumn();
// remove reference to instance
unset($db);
// doesn't require connection data now as it returns same instance again
$db = MyPdo::getInstance();
$version = $db->query( 'SELECT version();' );
echo $version->fetch();

Categories