I'm trying to re-code a homepage I made. This time I want to use OOP style, but I always get following error:
Statistic::checkExistingCounter() [statistic.checkexistingcounter]: Couldn't fetch MySQL
What am I doing wrong? I know that the prepare statement is senseless, but even just a query instead of prepare statement is not working at all.
Same error:
Couldn't fetch MySQL
My Database class:
class MySQL extends MySQLi {
private static $_instance = null;
private $host, $username, $password, $db;
public static function getInstance() {
if (!(self::$_instance instanceof self)) {
self::$_instance = new self();
}
return self::$_instance;
}
public function __construct(){
$this->host = '...';
$this->username = '...';
$this->password = '...';
$this->database = '...';
$this->connect();
}
public function __destruct() {
$this->db->close();
}
private function __clone(){}
public function connect() {
$this->db = #new MySQLi($this->host, $this->username, $this->password, $this->database);
/* change character set to utf8 */
$this->db->set_charset("utf8");
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
return $this->db;
}
}
My statistic class:
class Statistic {
private $remote, $user_agent, $referer;
private $db;
/**
* Create Instance of MySQL
**/
function __construct($db) {
$this->db = MySQL::getInstance();
}
/**
* Check for counter today
*
* #param: string SQL
* #return: boolean (true = Counter exists, false = Counter doesnt exist)
**/
function checkExistingCounter($sql) {
$stmt = $this->db->prepare($sql);
$this->db->error;
if (!$stmt) {
echo 'Datenbankfehler';
exit;
}
$stmt->execute();
$stmt->store_result();
if ($stmt->num_rows) {
$stmt->close();
return true;
} else {
$stmt->close();
return false;
}
}
function counter() {
$sql = "SELECT ID FROM Counter WHERE Datum = CURDATE()";
$checkCounter = $this->checkExistingCounter($sql);
}
And this is a part of my index.php:
$db = new MySQL();
$statistic = new Statistic($db);
$statistic->counter();
You seem to be in a muddle here, implementing two sets of competing coding patterns:
your MySQL class both extends MySQLi (that is, any MySQL object is also a MySQLi object) and "delegates" to a MySQLi instance in its private variable $db
your Statistic class takes an instance of MySQL in its constructor ("dependency injection"), but then ignores it and asks the MySQL class for a "singleton" instance.
You need to read up more carefully on what each of these patterns is for, and decide on one or the other in each case (inheritance or delegation, dependency injection or singletons).
Currently, your code will do the following:
create a new MySQL object (which is also a MySQLi object, but hasn't been initialised to any particular database connection, because you haven't called parent::__construct())
in the MySQL constructor, set $this->host etc
in the connect() method, create a new MySQLi object, passing it the host etc
save this object as $this->db, which is only ever referenced in the destructor ($this->db->close())
return the MySQLi object from connect(), but nothing in __construct() is looking at that return value
back in the outer code, the MySQL object is passed to the constructor of the Statistic class
the constructor then ignores this, and calls the Singleton method MySQL::getInstance() instead
the getInstance() method (since this is the first time it has been called) will create a second MySQL object, repeating steps 1 to 5
this second MySQL object will be saved as $this->db on the Statistics object
the checkExistingCounter method attempts to use $this->db as a MySQLi connection, but the MySQL object was never connected to any database, so you get an error. (There is a connected connection, and if it wasn't private, you could access it as $this->db->db. There's another one kicking around as well, which was created at step 2, but you can't access that any more, because you ignored it at step 7.)
Related
This is in reference to a CentOS 7 server running PHP 5.4 and MariaDB 5.5.
I am somewhat new to OOP in PHP. In converting a bunch of scripts from MySQL to MySQLi and from procedural database functions to OOP, I set up this basic Database class:
class Database
{
private $host = "localhost";
private $username;
private $password;
private $database;
private $dbconnect;
function __construct()
{
// Load config file for database connection info
$ini = parse_ini_file("config.ini");
$this->username = $ini['db.user'];
$this->password = $ini['db.pword'];
$this->database = $ini['db'];
}
public function connect()
{
// Only make a new connection if one not already established.
if (empty($this->dbconnect)) {
$mysql = new mysqli($this->host, $this->username, $this->password, $this->database);
if ($mysql->connect_errno) {
throw new appError($mysql->connect_error);
}
$this->dbconnect = $mysql;
}
return $this->dbconnect;
}
public function query($query)
{
$db = $this->connect();
$result = $db->query($query);
if ($db->errno) return false;
return $result;
}
public function select($query)
{
$rows = array();
$result = $this->query($query);
if ($result === false) return false;
// Create array with results
while ($row = $result->fetch_assoc()) {
$rows[] = $row;
}
return $rows;
}
}
With the former procedural database functions that used mysql_*, a persistent database connection was made near the start of the script and the resource ID was stored in a global variable, then all queries were run through that one database connection by accessing the global resource variable. Importantly, this worked well from within other functions and objects. Here's how that function worked:
function db_connect() {
if (!empty($GLOBALS['DBCONNECT']) && is_resource($GLOBALS['DBCONNECT'])) {
return $GLOBALS['DBCONNECT'];
} else {
$result = mysql_connect("localhost", DB_USER, DB_PASSWORD);
$GLOBALS['DBCONNECT'] = $result;
return $result;
}
}
So at the start of each script I'd do this...
db_connect();
And then run my queries like this...
$result = mysql_query($query, db_connect());
This made sure one database connection was made and that all queries are run through that connection.
With the above new Database class, I instantiate it at the start of my script...
$db = new Database;
$db->connect();
But I don't understand how to make that Database object accessible to other objects that need to perform database queries so that the same database connection is used by the entire script. What I do now is essentially this...
class MyClass
{
public function myFunction()
{
$db = new Database;
$data = $db->select("SELECT * FROM mydata WHERE id = 888");
...
}
}
This instantiates a new Database object within the above class, which is creating a new and additional connection to the database, because it can't access the Database $db object created in the parent calling script (that I know of).
Is there a way to use an object to open a persistent MySLQi database connection that all functions and objects loaded by that script can use? Or is this just something that is better done with a procedural function rather than a class and object? Does the solution lie in making the Database properties and its methods static? If I do that, I'm not sure how I load the database username and password from the config.ini file which the connect() function needs and is only done upon instantiation of the Database object.
I guess the basic question here is how do I access the properties or methods in an instantiated object from another object? Or maybe that isn't the question and I'm completely missing something else. Thanks!
You can do something like that a static method with a only a single tone
<?php
/*
* Mysql database class - only one connection alowed
*/
class Database {
private $_connection;
private static $_instance; //The single instance
private $_host = "HOSTt";
private $_username = "USERNAME";
private $_password = "PASSWORd";
private $_database = "DATABASE";
/*
Get an instance of the Database
#return Instance
*/
public static function getInstance() {
if(!self::$_instance) { // If no instance then make one
self::$_instance = new self();
}
return self::$_instance;
}
// Constructor
private function __construct() {
$this->_connection = new mysqli($this->_host, $this->_username,
$this->_password, $this->_database);
// Error handling
if(mysqli_connect_error()) {
trigger_error("Failed to conencto to MySQL: " . mysql_connect_error(),
E_USER_ERROR);
}
}
// Magic method clone is empty to prevent duplication of connection
private function __clone() { }
// Get mysqli connection
public function getConnection() {
return $this->_connection;
}
}
and to make a connection to the database and make a query simple use the lines:
$db = Database::getInstance();
$mysqli = $db->getConnection();
$sql_query = "SELECT foo FROM .....";
$result = $mysqli->query($sql_query);
There are a few options, one simple one (and likely the preferred) would be to use a static factory method in your database class that returns a previously initialized instance of the database class.
class Database
{
//static instance of the class
private static $instance;
public static function getDB()
{
//if the instance is not set, set it
if(is_null(self::$instance))
{
self::$instance = new Database();
self::$instance->connect();
}
return self::$instance;
}
//rest of your class below
}
This static method can be called from anywhere in any context and would allow for getting the same connected instance of the database. Just call $db = Database::getDB() anywhere you need it. For example:
function TestFunction()
{
//get an instance to the database
$dbInstance = Database::getDB();
//then use the database object like you normally would.
$dbInstance->query("SELECT * FROM `someTable`");
}
class TestClass
{
public function doSomething()
{
//get an instance to the database
$dbInstance = Database::getDB();
//then use the database object like you normally would.
$dbInstance->query("SELECT * FROM `someTable`");
}
}
$tc = new TestClass();
$tc->doSomething();
Another option, and one that I use for simplicity, is declare your connection static and reference that everywhere in your database class for queries and such. This allows for creating $db = new Database() anywhere and will just use the same connection. I've had this frowned upon as if it were same as a global because you can really only connect to one database (subsequent connections would overwrite the connection variable) But it worked for me and I didn't need multiple connections. I also like it that I can have each instance remember whatever queries were run on that instance and have a private count of the queries run.
I'm new to classes and PDO as well. I'm trying to write a class with separate functions for connecting to the db and closing the connection so that, in a page, I can:
Open the connection with the $db->connOpen
Perform all the queries I need inside the page
Close the connection at the end of the script with $db->connClose
class database
{
private $host = '';
private $db_name = '';
private $charset = '';
private $username = '';
private $password = '';
public function setHost($host) {
$this->host = $host;
}
public function setDbName($db_name) {
$this->db_name = $db_name;
}
public function setUser($username, $password) {
$this->username = $username;
$this->password = $password;
}
public function connOpen() {
try {
$dsn = "mysql:host=$this->host;dbname=$this->db_name;charset=$this->charset";
$db = new PDO($dsn, $this->username, $this->password, array(PDO::ATTR_PERSISTENT => true));
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo $e->getMessage();
}
}
public function connClose() {
$db = null;
}
}
I guess the problem is regarding more the classes syntax than the PDO, since to fire a query like the one below into the page I would need to instantiate again the class PDO, doubling the connection to the db.
$stmt = $dbo->prepare('SELECT * FROM products WHERE id=:id');
$stmt->execute(array(':id' => $id));
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
My questions are:
How can achieve what I want using a class like the one above?
Is it correct, in this case, using a persistent connection?
Thanks
For some reason, most people who wants to learn OOP starts with a database wrapper that implements singleton and interferes with error handling.
My tip is that you treat the database connection as any other variable:
class Post {
function getByUserId(PDO $connection, $user_id) {
}
}
$database = new PDO(...);
$post->getByUserId($database, 123);
This is called dependency injection.
And don't waste time and energy writing code to avoid useful features, such as:
Centralised error handling
Being able to connect to more than one database
Only care about writing a database wrapper when you really have real features to add on top of PDO. I can think of:
Convert dates to DateTime objects automatically
Pass all queries to a logger
Throw custom exceptions on interesting events, such as duplicate index violation
... and even then be extremely careful to not make PDO worse ;-)
I am using this with one singlton class which give me db ojbect and then I am using that object to query in other classes;
<?php
class db{
/*** Declare instance ***/
private static $instance = NULL;
/**
*
* the constructor is set to private so
* so nobody can create a new instance using new
*
*/
private function __construct() {
/*** maybe set the db name here later ***/
}
/**
*
* Return DB instance or create intitial connection
*
* #return object (PDO)
*
* #access public
*
*/
public static function getInstance() {
if (!self::$instance)
{
self::$instance = new \PDO("mysql:host=".databaseHost.";dbname=".databaseName."", databaseUserName,databasePassword);;
self::$instance-> setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
self::$instance-> setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
}
return self::$instance;
}
/**
*
* Like the constructor, we make __clone private
* so nobody can clone the instance
*
*/
private function __clone(){
}
} /*** end of class ***/
?>
class where i am querying using db object
<?php
class posts {
public function getPostOfUserId($userId,$offset=0,$limit=NULL){
$helperString=" ";
if(!empty($limit))
$helperString=" LIMIT $offset, $limit ";
$executor= db::getInstance()->prepare("SELECT posts.*,users.facebook_id, users.first_name as post_by FROM posts JOIN tagged_friends ON posts.id = tagged_friends.post_id JOIN users ON posts.user_id = users.id WHERE tagged_friends.user_id = :user_id ORDER BY posts.id DESC ".$helperString, array(\PDO::ATTR_CURSOR => \PDO::CURSOR_FWDONLY));
$executor->execute(array(':user_id'=>$userId));
$posts=$executor->fetchAll(\PDO::FETCH_ASSOC);
if(!empty($posts))
return $posts;
else
return ;
}
}
I am trying to return a new instance of my User class via a DAO, and am struggling to see if it is working, it certainly isn't working as I expected, as I am not defining User properties, yet I am still seeing all the User fields and values from the database.
class Database
class Database
{
private $dbh;
public function __construct()
{
$this->openConnection();
}
private function openConnection()
{
try {
$this->dbh = new PDO('mysql:host=localhost; dbname=stats', 'user', 'pass');
$this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
'There was an error connecting to the database, error: ' . $e->getMessage();
}
}
public function query($sql, $params)
{
$stmt = $this->dbh->prepare($sql, $params);
$stmt->execute($params);
return $stmt;
}
}
class UserDao
class UserDao
{
private $db;
public function __construct($db)
{
$this->db = $db;
}
public function findById($ward_code)
{
$record = $this->db->query("SELECT * from ward_statistics where WardCode = :WardCode", array(':WardCode' => $ward_code));
$record->setFetchMode(PDO::FETCH_CLASS, 'User')
$user = $record->fetch();
return $user;
}
}
class User
class User
{
// with no properties defined, I still get a
// full result set from UserDAO::findById()
}
Usage
$db = new Database();
$dao = new UserDao($db);
$user = $dao->findById('AMED');
var_dump($user);
Results in an object with a full result set from the DB (a single row that is - matched by the WardCode), with all fields populated with the correct values (from the DB).
Whilst this seems OK - I thought that PDO::FETCH_CLASS required the properties to available within the class.
My worry is, from a question I posted on Code Review a few days ago, I was also told that class methods such as the findById one should create new class instances, or update the existing one, yet all I seem to be doing is retrieving a row from the database.
Thanks
Replace fetchAll with fetch if you need just 1 object. According to documentation:
PDOStatement::fetchAll — Returns an array containing all of the result
set rows
I have just started learning the concept of Object oriented programming and I've written this class with functions.
It works fine, but I'm interested in knowing if I have done this correctly...
Here is my code:
class Database{
const DB_HOSTNAME = 'localhost';
const DB_USERNAME = 'root';
const DB_PASSWORD = 'password';
const DB_NAME = 'shop';
protected $_db_connect;
protected $_sql;
protected $_result;
protected $_row;
function db_connect(){
$this->_db_connect = mysql_connect(self::DB_HOSTNAME,self::DB_USERNAME,self::DB_PASSWORD) or die(mysql_error());
}
function slect_db(){
mysql_select_db(self::DB_NAME) or die(mysql_error());
}
function sql(){
$this->_sql = 'SELECT * FROM users';
}
function query(){
$this->_result = mysql_query($this->_sql);
}
function fetch_array(){
while($this->_row = mysql_fetch_array($this->_result)){
$username = $this->_row['user_USERNAME'];
echo "<ul>";
echo "<li>".$username."</li>";
echo "</ul>";
}
}
function db_close(){
mysql_close($this->_db_connect);
}
}
$database = new Database();
$database->db_connect();
$database->slect_db();
$database->sql();
$database->query();
$database->fetch_array();
$database->db_close();
Please use PDO or MySQLi as it's more secure and mysql_* functions are deprecated as stated above, I've provided some generic code using PDO to help you with that new venture. As stated in the comments, you really shouldn't be echoing out the data if you're looking for an object oriented design, what you should be doing is after you do the query, return the rows that you fetched and from there use something such as a foreach loop to then display your data. Doing your database class this way will also make sure that multiple database connections aren't open at once! Note, this code is just for you to reference, and should be tested before use in production or anything live.
config.php:
<?php
//Enter your database connection details here.
$host = 'localhost'; //HOST NAME.
$db_name = 'databasename'; //Database Name
$db_username = 'root'; //Database Username
$db_password = ''; //Database Password
try
{
$pdo = new PDO('mysql:host='. $host .';dbname='.$db_name, $db_username, $db_password);
}
catch (PDOException $e)
{
exit('Error Connecting To DataBase');
}
?>
database.class.php:
<?php
class database
{
function __construct($pdo)
{
$this->pdo = $pdo;
}
function getData()
{
$query = $this->pdo->prepare('SELECT * FROM database');
$query->execute();
return $query->fetchAll();
}
}
?>
index.php:
<?php
require_once 'config.php';
require_once 'database.class.php';
$db = new database($pdo);
$rows = $db->getData();
?>
It is possible to improve the way you connect to databases using autoloading and dependency injection containers. Here is a way of using Auryn to connect to your database while being sure there is only one connection opened and not having to manually require files throughout your application.
I will cover only PDO and Auryn here. There are other dependency injection containers and notably the mysqli extension to connect to database, but the content should help you using another container if you wish to do so.
The database class
Having a database class is superfluous. The \PDO class is already providing all necessary methods to query the database. Having a database class makes you repeat the functions it provides and limits your actions (or makes you create many functions) when you want to for example use multiple different fetch styles depending on your needs in a specific method.
Dependency Injection
If you haven't already, have a read on dependency injection. The point is that when a class needs to access the database, it should not have to bother constructing the \PDO object, it should be constructed with it:
class Mapper {
private $pdo;
public function __construct(\PDO $pdo) {
$this->pdo = $pdo;
}
public function createFromId($id) {
$stmt = $this->pdo->prepare("SELECT name FROM foo WHERE id=:id");
$stmt->execute([
":id" => $id,
]);
return $stmt->fetchObject();
}
}
Notice that I directly pass the \PDO object, not a wrapper class. That way, I always have access to all of its capabilities, not only a subset of user-defined functions.
Dependency Injection Container
A dependency injection container helps build your classes, giving them the objects they need, and giving you great flexibility on how to actually build those objects. Here I'll only focus on configuring and sharing a \PDO object through the use of Auryn.
I assume you have installed the required Auryn class, the easier way is using composer. This is out of the scope of this answer, there are multiple resources on how to use it.
Create the injector
$injector = new \Auryn\Injector();
Define the \PDO class parameters
$injector->define("PDO", [
":dsn" => "mysql:host=localhost;charset=utf8;dbname=dbname",
":username" => "user",
":passwd" => "passwd",
":options" => [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
],
]);
You can either write the configuration parameters directly here, or get them from a config file. I like having a config.ini file and using parse_ini_file() to get my configuration options, as I can easily switch databases by editing a config file.
Share the \PDO object
$injector->share("PDO");
This part is really important. This lines makes the injector give the same \PDO object every time it is tasked with constructing a class that needs a connection. Note that the order of the lines is not important, you can share the class before defining it, only make sure to create you database needing classes after writing both those lines.
Create your objects
$mapper = $injector->make("Mapper");
That's it. The injector will create your mapper object, creating the \PDO object if it haven't already been, passing the existing instance if it has.
Autoloading
Assuming you have used composer, you can make use of its great autoloader. Otherwise you can also roll you own autoloader.
The point here is to stop having require() everywhere in your code, especially if you have complex class hierarchies, which you should have in a single responsibility compliant class system.
Wrapping up
With this set up, you now can use the \PDO object in your classes while being assured there will only be one instance per request, without the need to require files everywhere, and without using a singleton anti-pattern.
$database = new Connection();
class Connection
{
function __construct()
{
switch($_SERVER['DOCUMENT_ROOT'])
{
case 'path':
$this->host = 'hostname';
$this->user = 'username';
$this->passwd = 'password';
$this->database = 'dbname';
break;
default :
$this->host = 'localhost';
$this->user = 'root';
$this->passwd = 'root';
$this->database = 'dbname';
break;
}
$this->clink = #mysql_connect($this->host,$this->user,$this->passwd);
#mysql_select_db($this->database,$this->clink);
}
}
$objConn = new mysqlconnect();
$Conn = $objConn->setobjConnect("localhost","root","P#ssw0rd");
class Database{
var $last_query; //Saved result of the last query made
var $last_result; //Results of the last query made
var $func_call; //A textual description of the last query/get_row/get_var call
var $link; //database link
var $lastquery; //last query
var $result; //query result
// Connect to MySQL database
function database() {
$this->link=mysql_connect(DB_HOST, DB_USER, DB_PASS) or die('Server connexion not possible.');
//Set All Charsets to UTF8
mysql_query("SET character_set_results=utf8 , character_set_client=utf8 , character_set_connection=utf8 , character_set_database=utf8 , character_set_server=utf8");
mysql_select_db(DB_NAME) or die('Database connection not possible.');
}
/** Query the database.
* #param $query The query.
* #return The result of the query into $lastquery, to use with fetchNextObject().
*/
function query( $query ){
$this->lastquery=$query;
$this->result=#mysql_query( $query, $this->link );
return $this->result;
}
/** Do the same as query() but do not return nor store result.
* Should be used for INSERT, UPDATE, DELETE...
* #param $query The query.
* #param $debug If true, it output the query and the resulting table.
*/
function execute($query)
{
#mysql_query($query);
}
/** Convenient method for mysql_fetch_object().
* #param $result The ressource returned by query().
* #return An ARRAY representing a data row.
*/
function fetchArray($result){
if ($result == NULL)
$result = $this->result;
if ($result == NULL || mysql_num_rows($result) < 1)
return NULL;
else
return mysql_fetch_assoc($result);
}
/** Close the connecion with the database server.
* It's usually unneeded since PHP do it automatically at script end.
*/
function close()
{
mysql_close($this->link);
}
/** Get the number of rows of a query.
* #param $result The ressource returned by query(). If NULL, the last result returned by query() will be used.
* #return The number of rows of the query (0 or more).
*/
function numRows($result = NULL)
{
if ($result == NULL)
return #mysql_num_rows($this->result);
else
return mysql_num_rows($result);
}
}
![<?php
class mysqlconnect{
private $server=null;private $user=null;private $password=null;private $objConnect=null;
function setobjConnect($s,$u,$p){
$this->server = $s;
$this->user = $u;
$this->password = $p;
return $this->objConnect = mysql_connect($this->server,$this->user,$this->password);
}
}
$objConn = new mysqlconnect();
$Conn = $objConn->setobjConnect("localhost","root","P#ssw0rd");
if($Conn)
{
echo "Database Connect";
}
else
{
echo "Database Connect Failed.";
}
mysql_close($Conn);
?>]
1
I'm trying to switch from building query strings and calling mysql_query() and embrace PDO. I've read a handful of tutorials, and understand the basic process of preparing a statement and assigning values to the placeholders.
What I don't understand is how to integrate this new technique into my existing web app.
Let me explain:
currently, I've got an init.php which is require_once'd on every page. It holds the database U/P and opens the database connection. With that loaded, I can sling queries left and right, willy AND nilly, anywhere I please without any further thought.
PDO strikes me as a much more deliberate approach. Do I still stuff all the U/P and connection handlers into my init file? Can I just work through my scripts and replace queries one-to-one with PDO statements?
Sorry for the simple question!
For what it is worth, I had the same issue and this is how I approached it. I divided the database functions into two different classes, Database and Query. I setup and open the database in my init function and then call instances of my Query class throughout the page, closing the queries each time I am done. Finally, I close the database.
The actual classes I use have some more error checking and other stuff I specifically, but here are the drafts I uses when putting the scheme together. Maybe it will be useful to you.
Database Class:
<?php
class Database {
private $db, $dbserver, $dbport, $dbname, $dbuser, $dbpassword;
//----------------------------------------------------------------------------------------------------------
//Function: __construct()
//----------------------------------------------------------------------------------------------------------
public function __construct($idbserver, $idbport, $idbname, $idbuser, $idbpassword)
{
$this->dbserver = $idbserver;
$this->dbport = $idbport;
$this->dbname = $idbname;
$this->dbuser = $idbuser;
$this->dbpassword = $idbpassword;
}
//----------------------------------------------------------------------------------------------------------
//Function: openDatabase()
//----------------------------------------------------------------------------------------------------------
public function openDatabase()
{
/* Create a new user db object with persistent database connection parameters */
try {
$this->db = new PDO("mysql:host=".$this->dbserver.";dbname=".$this->dbname.";port=".$this->dbport, $this->dbuser, $this->dbpassword, array(
PDO::ATTR_PERSISTENT => true
));
return true;
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
}
//----------------------------------------------------------------------------------------------------------
//Function: getDB
//----------------------------------------------------------------------------------------------------------
public function getDB()
{
//return the database
return $this->db;
}
//----------------------------------------------------------------------------------------------------------
//Function: getDBName
//----------------------------------------------------------------------------------------------------------
public function getDBName()
{
//return the database
return $this->dbname;
}
//----------------------------------------------------------------------------------------------------------
//Function: closeUserDatabase
//----------------------------------------------------------------------------------------------------------
public function closeDatabase()
{
//close the database
$this->db=null;
}
}
?>
Then my Query Class:
<?php
class Query {
private $db, $sql, $qresult;
//----------------------------------------------------------------------------------------------------------
//Function: __construct
//----------------------------------------------------------------------------------------------------------
public function __construct($idb, $isql)
{
$this->db = $idb;
$this->sql = $isql;
}
//----------------------------------------------------------------------------------------------------------
//Function: openQuery
//----------------------------------------------------------------------------------------------------------
public function openQuery($param)
{
/* assemble and run a query and return a result object */
//prepare the sql statement
//get the db object
$tempdb= $this->db->getDB();
$this->qresult = $tempdb->prepare($this->sql);
//bind parameters to the prepared statement
foreach ($param as $key => $value) {
$this->qresult->bindValue($key,$value);
}
return $this->qresult->execute();
}
//----------------------------------------------------------------------------------------------------------
//Function: fetchAssociative
//----------------------------------------------------------------------------------------------------------
public function fetchAssociative()
{
return $this->qresult->fetch(PDO::FETCH_ASSOC);
}
//----------------------------------------------------------------------------------------------------------
//Function: closeQuery
//----------------------------------------------------------------------------------------------------------
public function closeQuery()
{
$this->qresult = null;
}
}
?>
Then I set up the database in my init function:
//initialize the user database with buffered set true so we can use nested queries
$usrdb = new Database($udbserver, $udbport, $udbname, $udbuser, $udbpassword, array(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true));
//open the database
$usrdb->openDatabase();
Then I call my query in the page:
//set up the sql
$sql = "SELECT * FROM Blah WHERE blahid = :filter";
//create the parameter array
$params = array(':filter'=>$filter);
//craetea new query
$q = new Query($usrdb, $sql);
//run the query
if ($q->openQuery($params)) {
//get the results if there are any
while ($row=$q->fetchAssociative()) {
$viewData['blahid']=$row['blahid'];
}
}
//clean up the query
$q->closeQuery();
After that I work with the results just like I always used to.
PDO works same way as old school approach. You still need to define connection and initialise object in order to query database.
I store the PDO database connection and retrieve an instance of it as a singleton.
Any place you need your database, to run a query or execute prepared statements, you use the singleton instance.
$db_handle = PDO_DBConnect::getInstance();
$stmt = $db_handle->prepare("SELECT * FROM users WHERE name= ?");
$result = $stmt->execute(array($cleaned_username));
...
If a class has multiple queries, you can store the handle in an instance variable,
$this->dbh = PDO_DBConnect::getInstance();
for convenience.
One other note is unlike pg_close or mysql_close, there is no close method for PDO. You simply set the db handle to null.