I have created a database class which is throwing an error of
Undefined variable: options in C:path/ on line 21
and I cant seem to figure out why.
class Db
{
private static $instance = null;
private $options = array(
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
);
private function __construct() {}
private function __clone() {}
public static function getInstance()
{
if (!isset(self::$instance)) {
self::$instance = new PDO('mysql:host=localhost;dbname=mydb', 'root', '', $options);
}
return self::$instance;
}
}
Your $options doesn't exist. You should reference the defined one as $this->options, but that's not a solution for you as you are using it in a static function: the $this context is not available.
You could just define your options in that static method I guess, like below. Not the prettiest solution as now your settings are hidden in your creation-method, but as an example:
class Db
{
private static $instance = null;
private function __construct() {}
private function __clone() {}
public static function getInstance()
{
$options = array(
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
);
if (!isset(self::$instance)) {
self::$instance = new PDO('mysql:host=localhost;dbname=mydb', 'root', '', $options);
}
return self::$instance;
}
}
The error by the way is quite clear: you are using a variable $options that doesn't exist at that point so you get an error that says it's not defined.
Related
I'm trying to figure out how to get the last insert id with the database class I'm using and can't seem to get it right. Keep getting "Call to undefined method PDOStatement::lastInsertId()"
Here's how I call it.
require_once '../classes/pdo.php';
$sql="insert into accounts(account_email,account_password) values(:email,:password)";
$values=array(':email'=>'jay.garrick#email.com',':password'=>'blah');
$res = DB::run($sql,$values);
$id = $res->lastInsertId();
echo $id;
Here's my class.
class DB {
protected static $instance = null;
protected function __construct() {}
protected function __clone() {}
public $pdo;
public $lastInsertId = null;
public static function instance()
{
if(self::$instance == null)
{
$opt = array(
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
);
//$options = array_replace($default_options,$options);
$dsn = 'mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset='.DB_CHAR;
self::$instance = new PDO($dsn, DB_USER, DB_PASS, $opt);
}
return self::$instance;
}
public static function __callStatic($method, $args)
{
return call_user_func_array(array(self::instance(), $method), $args);
}
public static function run($sql, $args = NULL)
{
if(!$args)
{
return self::instance()->query($sql);
}
$stmt = self::instance()->prepare($sql);
$stmt->execute($args);
return $stmt;
}
}
This question already has an answer here:
php function returns null instead of string [duplicate]
(1 answer)
Closed 3 years ago.
I just tried a PDO wrapper from https://phpdelusions.net/pdo/pdo_wrapper.
First the PDO Wrapper
class MyPDO
{
protected static $instance;
protected $pdo;
public function __construct() {
$opt = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ,
PDO::ATTR_EMULATE_PREPARES => FALSE,
);
$dsn = 'mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset='.DB_CHAR;
$this->pdo = new PDO($dsn, DB_USER, DB_PASS, $opt);
}
// a classical static method to make it universally available
public static function instance()
{
if (self::$instance === null)
{
self::$instance = new self;
}
return self::$instance;
}
// a proxy to native PDO methods
public function __call($method, $args)
{
return call_user_func_array(array($this->pdo, $method), $args);
}
// a helper function to run prepared statements smoothly
public function run($sql, $args = [])
{
if (!$args)
{
return $this->query($sql);
}
$stmt = $this->pdo->prepare($sql);
$stmt->execute($args);
return $stmt;
}
}
and then the user class
class User
{
/* #var MyPDO */
protected $db;
protected $data;
public function __construct()
{
$this->db = MyPDO::instance();
}
public function find($id)
{
$this->data = $this->db->run("SELECT * FROM user_account WHERE id = ?", [$id])->fetch();
}
}
and then instantiate class user
$user = new User();
$a = $user->find(3);
var_dump($a);
There is a record associated with ID = 3 but the result I get is NULL, why?
As mentioned in the comments, the find method doesn't return anything, it is probably storing it just fine in $this->data but is never returned.
public function find($id)
{
$this->data = $this->db->run("SELECT * FROM user_account WHERE id = ?", [$id])->fetch();
return $this->data;
}
The discussion of using a Singleton or not is out of scope for this question.
That said, I've found online multiple database connection classes using PDO and following the singleton pattern.
Here is one for example :
<?php
define('DB_HOST', 'localhost');
define('DB_NAME', 'test');
define('DB_USER', 'root');
define('DB_PASS', '');
define('DB_CHAR', 'utf8');
class DB
{
protected static $instance = null;
protected function __construct() {}
protected function __clone() {}
public static function instance()
{
if (self::$instance === null)
{
$opt = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => FALSE,
);
$dsn = 'mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset='.DB_CHAR;
self::$instance = new PDO($dsn, DB_USER, DB_PASS, $opt);
}
return self::$instance;
}
public static function __callStatic($method, $args)
{
return call_user_func_array(array(self::instance(), $method), $args);
}
public static function run($sql, $args = [])
{
if (!$args)
{
return self::instance()->query($sql);
}
$stmt = self::instance()->prepare($sql);
$stmt->execute($args);
return $stmt;
}
}
However, according to this Stackoverflow answer Is it necessary to close PDO connections
, some users suggest that it's a good practice to close all connections at the end of the script.
So:
1. Why does no one include a destroy/close method?
2. How would it be done right (destroying a PDO inside a singleton?)
My approach would have been:
class DB
{
// ... the whole singleton
public static function close()
{
self::$instance = null;
return null;
}
}
$pdo = DB::getInstance();
// do stuff
$pdo = DB::close($pdo);
This question already has answers here:
PHP parse/syntax errors; and how to solve them
(20 answers)
Closed 7 years ago.
Hi i am using PDO DB class to connect to database. But i really wonder if i am doing it correct or not. All connection set up is fine but i get error when i run a query
My Directory Structure is
/root
/dbops <-- Directory contains `config.php` -->
/dbfunctions <-- Directory contains `DBclass.php` & `DBFuncts.php` -->
Now contents of config.php are:
define( 'DB_HOST', 'localhost' );
define( 'DB_USERNAME', 'root');
define( 'DB_PASSWORD', '');
define( 'DB_NAME', 'testDB');
define('DB_CHAR', 'utf8');
function __autoload($class){
$parts = explode('__', $class);
$path = implode(DIRECTORY_SEPARATOR,$parts);
require_once $path . '.php';
}
DBclass.php contains:
class dbdunctions__DBclass{
public $instance = null;
public function __construct() {}
final private function __clone() {}
public static function instance()
{
if (self::$instance === null)
{
$opt = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => TRUE,
PDO::ATTR_STATEMENT_CLASS => array('myPDOStatement'),
);
$dsn = 'mysql:host='.DB_HOST.';dbname='.DB_NAME.';
charset='.DB_CHAR;
self::$instance = new PDO($dsn, DB_USERNAME, DB_PASSWORD,
$opt);
}
return self::$instance;
}
public static function __callStatic($method, $args) {
return call_user_func_array(array(self::instance(), $method), $args);
}
}
class myPDOStatement extends PDOStatement
{
function execute($data = array())
{
parent::execute($data);
return $this;
}
}
DBFuncts.php contains below:
class dbfunctions__DBFuncts
{
protected $_con;
public function __construct()
{
$db = new dbfunctions__DBclass();
$this->_con = $db->con;
}
function gotodb(array $data){
$result =
$this->_con::instance()->prepare($qry)->execute(array(/*parameters*/));
}
}
Now when query is fired with $result then i get following error
Parse error: syntax error, unexpected '::' (T_PAAMAYIM_NEKUDOTAYIM) in dbops/dbfunctions/DBFuncts.php on line 12
Please guide. I have already spent 2 hrs on this issue and googling around.
Instead of
$this->_con::instance()
You should be able to just do
$this->_con->instance()->prepare($qry)->execute(array(/*parameters*/));
Not sure if it's a typo for when you put the code in - but I did notice that in the DBclass.php you have class dbdunctions__DBclass - surely this should be class dbfunctions__DBclass() ?
Also there seems to be some other errors in your example code ... But lets tackle them one at a time :)
Try adjusting this way. I have it working on my server with some adjustments. Notably instantiating the connection in the __construct() of the dbdunctions__DBclass() class and assigning $this->_con to the self::$instance (dbdunctions__DBclass::$instance;):
class dbdunctions__DBclass
{
// Make the instance static
public static $instance = null;
public function __construct()
{
// Create the static connection in the construct
$this->init();
}
private function init()
{
if (self::$instance === null) {
$opt = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => TRUE,
PDO::ATTR_STATEMENT_CLASS => array('myPDOStatement'),
);
self::$instance = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.'; charset='.DB_CHAR, DB_USERNAME, DB_PASSWORD, $opt);
}
}
final private function __clone()
{
}
public static function __callStatic($method, $args)
{
return call_user_func_array(array(self::instance(), $method), $args);
}
}
class myPDOStatement extends PDOStatement
{
public function execute($data = array())
{
parent::execute($data);
return $this;
}
}
class dbfunctions__DBFuncts
{
protected $_con;
public function __construct()
{
// Create instance of database
$database = new dbdunctions__DBclass();
// Assign the connection to the $this->_con
$this->_con = dbdunctions__DBclass::$instance;
}
public function gotodb($statement = false,$bind = false)
{
// Incase the statement or bind is empty, return 0
if(empty($statement) || empty($bind))
return 0;
// Create the query with method chain
$query = $this ->_con->prepare($statement)
->execute($bind);
// Fetch results
while($row = $query->fetch())
$result[] = $row;
// If results return array else return 0 for consistency
return (!empty($result))? $result : 0;
}
}
// Instantiate
$dbFunc = new dbfunctions__DBFuncts();
// Use whatever you use to return a result here. This statement happens
// to work for my database...but likely not yours
print_r($dbFunc->gotodb("select * from `users` where `ID` = :ID",array(":ID"=>"29")));
class dbfunctions__DBFuncts
{
protected $_con;
public function __construct()
{
$db = new dbfunctions__DBclass();
$this->db = $db;
}
function gotodb(array $data){
$result =
$stmt = $this->db->prepare($qry);
$stmt->execute(array(/*parameters*/));
}
The PDO object gets created then made into a "member object". The gotodb object uses the "member object" PDO instance. Below is a sample of code from a site I'm working on which should help explain it better:
try {
$sql="
SELECT
id
, name
, description
FROM
ue_bug_project
";
// $stmt objected created by preparing the SQL query for execution, using the PDO object, which in this case is $this->db
$stmt = $this->db->prepare($sql);
// The execute method of the $stmt object is run executing the query, in this case no query data is bound as there is no user submitted data being used
$stmt->execute();
// The result set is grabbed in one hit and placed into the projects array (I really should have set up the $projects variable as an empty array beforehand)
$projects = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $projects;
}
// If the query fails with an error, the catch block is run, in this case i log the error.
catch (PDOException $e) {
error_log('Error when getting the list of projects!');
error_log(' Query with error: '.$sql);
error_log(' Reason given:'.$e->getMessage()."\n");
return false;
}
}
From the looks of your code there's probably no real need to place your own wrapper around the PDO class
I am a bit puzzled here, I am easing myself into oop and struggling a little. I have beenusing Aura SQL (php) and have achieved pretty much what I need, but, it has become necessary to connect to more than one DB to update some legacy code I have been passed.
class Core {
public $pdo;
private static $instance;
private function __construct() {
$this->pdo = new ExtendedPdo(
'mysql:host=localhost;charset=utf8;dbname=db',
'user',
'pass'
);
$this->pdo->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, 'SET NAMES utf8');
}
public static function getInstance() {
if (!isset(self::$instance)) {
$object = __CLASS__;
self::$instance = new $object;
}
return self::$instance;
}
}
I have tried to amend by passing the values in via the constructor, but, it seems to be ignored eg:
private function __construct($db_name) {
if !empty($db_name)) { $this->db = $db_name; } else { $this->db = 'default_db'; }
$this->pdo = new ExtendedPdo(
'mysql:host=localhost;charset=utf8;dbname='.$this->db.'',
....
Normally you would use getInstance(); but I have been trying instantiating a new object to access the other databases.
Thanks for any advice.
Please checkout the ConnectionLocator via which you can create default connection, and rest of the connections. Taking code snippet from the readme.
<?php
use Aura\Sql\ConnectionLocator;
use Aura\Sql\ExtendedPdo;
// default connection
$default = function () {
return new ExtendedPdo(
'mysql:host=default.db.localhost;dbname=database',
'username',
'password'
);
};
// read connections
$read = array(
'slave1' => function () {
return new ExtendedPdo(
'mysql:host=slave1.db.localhost;dbname=database',
'username',
'password'
);
},
'slave2' => function () {
return new ExtendedPdo(
'mysql:host=slave2.db.localhost;dbname=database',
'username',
'password'
);
},
'slave3' => function () {
return new ExtendedPdo(
'mysql:host=slave3.db.localhost;dbname=database',
'username',
'password'
);
},
);
// write connection
$write = array(
'master' => function () {
return new ExtendedPdo(
'mysql:host=master.db.localhost;dbname=database',
'username',
'password'
);
},
);
// configure locator at construction time
$connections = new ConnectionLocator($default, $read, $write);
$default_connection = $connections->getDefault();
$read_slave1_connection = $connections->getRead('slave1');
$read_any_connection = $connections->getRead();
$write_connection = $connections->getWrite();