How to properly write a database class in php with singleton pattern? - php

Today I did some modifications into my database class. One of them was to use singleton pattern but I'm not 100% sure if i'm doing it right since I have never done this before.
It seems to work tho but still not sure if it does what's supposed to do.
Here is a sample. What do you think? Any suggestions are welcome :)
<?php
class Database {
protected static $instance;
private static $dsn = DB_TYPE.":host=".DB_HOST.";dbname=".DB_NAME;
private static $username = DB_USER;
private static $password = DB_PASS;
private function __construct() {
try {
self::$instance = new PDO(self::$dsn, self::$username, self::$password);
self::$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
self::$instance->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
} catch (PDOException $e) {
die($e->getMessage());
}
}
private function __clone() { }
public static function getInstance() {
if(!self::$instance) {
new Database();
}
return self::$instance;
}
public function read($query, $data = [])
{
$DB = Database::getInstance();
$stm = $DB->prepare($query);
if($stm) {
$check = $stm->execute($data);
if($check) {
$result = $stm->fetchAll(PDO::FETCH_OBJ);
}
}
}
if(is_array($result) && count($result) > 0) {
return $result;
}
return false;
}
}
// test
echo '<pre>';
print_r(Database::read("SELECT * FROM table"));

Related

OUTPUT my Fetched Data to my Main Program in PHP OOP

I'm a newbie in PHP OOP. Can you please help me how to fix this code below because it gives me an infinite output. I want to output or echo my fetched data to my main program. Thanks.
===========================================
class DB {
private $_hostdb = 'localhost';
private $_namedb = 'imsdb';
private $_userdb = 'root';
private $_passdb = '';
private $_conn;
private static $_instance;
private $_rowResult;
private function __construct(){
try{
$this->_conn=new PDO("mysql:host=$this->_hostdb;dbname=$this- >_namedb",$this->_userdb,$this->_passdb);
$this->_conn->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
if($this->_conn){
echo "Connected Successfully!";
}
} catch (Exception $ex) {
echo ("Connection Failed!")."".$ex->getMessage();
}
}
public static function getInstance(){
if(!isset(self::$_instance))
{
return self::$_instance=new DB();
}
}
public function processQuery($sql){
try{
$q=$this->_conn->prepare($sql);
$q->execute();
$q->setFetchMode(PDO::FETCH_ASSOC);
return $this->_rowResult=$q->fetch(); //Is this correct??
} catch (Exception $ex) {
echo ("Failed!")." ".$ex->getMessage();
}
}
}
//MAIN PROGRAM -> OUTPUT gives me an infinite data which is wrong
$dbUser=DB::getInstance()->processQuery("SELECT * FROM users");
while($dbUser){
echo $dbUser['username'];
}
It tried code below but it gives me one record and it repeats 7 times.
OUTPUT: 1111111
===================================
class DB {
private $_hostdb = 'localhost';
private $_namedb = 'imsdb';
private $_userdb = 'root';
private $_passdb = '';
private $_conn;
private static $_instance; //must be static
public $rowResult;
private function __construct(){
try{
$this->_conn=new PDO("mysql:host=$this->_hostdb;dbname=$this- >_namedb",$this->_userdb,$this->_passdb);
$this->_conn- >setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
if($this->_conn){
echo "Connected Successfully!<br />";
}
//
} catch (Exception $ex) {
echo ("Connection Failed!")."<br />".$ex->getMessage();
}
}
public static function getInstance(){
if(!isset(self::$_instance))
{
return self::$_instance=new DB();
}
}
public function processQuery($sql){
try{
$q=$this->_conn->prepare($sql);
$q->execute();
$q->setFetchMode(PDO::FETCH_ASSOC);
return $this->rowResult=$q->fetch();
} catch (Exception $ex) {
return ("Failed!")."<br />".$ex->getMessage();
}
}
public function getResultSet(){
return $this->rowResult;
}
}
//MAIN PROGRAM
$dbUser=DB::getInstance();
$user=$dbUser->processQuery("SELECT * FROM users");
for($i=0;$i<count($dbUser->rowResult);$i++){
echo $user['id'];
}
Your while loop is infinite because it keeps processing $dbUser which returns true each time, it's equivalent to saying while(true)
You really want to access the result set via a getter method, so in your class you could add something like:
public function getResultSet() {
return $this->_rowResult;
}
I've edited this and modified the bits you have listed:
class DB {
...
public static function getInstance()
{
if (null === self::$_instance)) {
self::$_instance = new DB();
}
return self::$_instance; // Always return your instance, the if statement just sets it in the property if it's not already
}
public function processQuery($sql)
{
try {
$q = $this->_conn->prepare($sql);
$q->execute();
$q->setFetchMode(PDO::FETCH_ASSOC);
$this->rowResult = $q->fetchAll(); // Use fetchAll rather than fetch
} catch (Exception $ex) {
echo "Failed!", "<br />", $ex->getMessage();
}
}
...
}
And your main program:
//MAIN PROGRAM
$dbUser = DB::getInstance();
$user = $dbUser->processQuery("SELECT * FROM users");
foreach ($dbUser->getResultSet() as $user) {
print_r($user['id']);
}

PDO wont connect to the database

I've made a simple Database class to handle my database connections. But it's somehow not working? At first it wasn't working with MySQLi, so i tried PDO – which ain't working either.
I am however eager to make PDO work. I've already googled and searched here at StackOverflow, but without luck.
Here's my class:
class Database
{
// Local
protected $_host = "localhost";
protected $_user = "root";
protected $_pass = "root";
protected $_database = "hs";
protected $_connection;
// Construct
private function __construct()
{
try
{
$this->_connection = new PDO('mysql:host=localhost;dbname=hs', $this->_user, $this->_pass);
$this->_connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e)
{
echo 'ERROR: ' . $e->getMessage();
}
}
public function login($usr, $pwd)
{
echo "hi";
}
}
And here's the execution:
if(isset($_POST['hs_login']))
{
$db = new Database;
$db->login($_POST['hs_username'], $_POST['hs_password']);
}
Thanks in advance! :)
Constructors are always public so change that like so:
class Database
{
// Local
protected $_host = "localhost";
protected $_user = "root";
protected $_pass = "root";
protected $_database = "hs";
protected $_connection;
// Construct
public function __construct()
{
try
{
$this->_connection = new PDO('mysql:host=localhost;dbname=hs', $this->_user, $this->_pass);
$this->_connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e)
{
echo 'ERROR: ' . $e->getMessage();
}
}
public function login($usr, $pwd)
{
echo "hi";
}
}
Also, new Database is a method call so change that like so:
if(isset($_POST['hs_login']))
{
$db = new Database;
$db->login($_POST['hs_username'], $_POST['hs_password']);
}
Just wanted to point out, that there are some cases, when you can use private constructors. One of the practical use of them is with Databases, so it's relevant in your case as well. This design pattern is called Singleton pattern, and it relies on static method calls. You don't have to instantiate the class, as instantiation is handled by the class itself. I've put together an example:
<?php
class Database {
private static $instance = null;
private $db;
private static $last_result;
private function __construct() {
try {
$pdo_param = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
);
$this->db = new PDO("mysql:host=YOUR_HOSTNAME;dbname=YOUR_DBNAME", "YOUR_USERNAME", "YOUR_PASSWORD", $pdo_param);
}
catch (PDOException $e) {
die($e->getMessage());
}
}
private static function getInstance() {
if (self::$instance == null) {
self::$instance = new self();
}
return self::$instance;
}
public static function query($sql) {
try {
$instance = self::getInstance();
$stmt = $instance->db->prepare($sql);
$stmt->execute();
self::$last_result = $stmt->fetchAll();
return self::$last_result;
}
catch (PDOException $e) {
die($e->getMessage());
}
}
public static function prepare($sql, $params) {
try {
$instance = self::getInstance();
$stmt = $instance->db->prepare($sql);
$stmt->execute($params);
self::$last_result = $stmt->fetchAll();
return self::$last_result;
}
catch (PDOException $e) {
die($e->getMessage());
}
}
}
$users = Database::query("SELECT * FROM users");
$filtered_users = Database::prepare("SELECT * FROM users WHERE username = :username", array(":username" => "john_doe"));
?>
<pre><?php
print_r($users);
print_r($filtered_users);
?></pre>
Singleton design pattern is really useful when you want to make sure, that there's ONLY ONE instance of a class in any given time.

PHP - pass PDO connection to all functions

I have a try catch block that connects via PDO to a database. I would like to be able to reference it in all my functions without having to pass it as a parameter. How would I do this? The mentioned code is:
try {
$database = new PDO('mysql:host=127.0.0.1;dbname=coop1','root','');
$database->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}catch(PDOException $e) {
echo $e->getmessage();
die();
}
EDIT:
I created a singleton class (attempt below) that executes the try catch block upon _construct
final class database {
private static $instance = NULL;
private function __construct() {
try {
$database = new PDO('mysql:host=127.0.0.1;dbname=coop1','root','');
$database->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
echo $e->getmessage();
die();
}
}
public static function getInstance() {
static $instance = null;
if (self::$instance === NULL) {
$instance = new database();
}
return $instance;
}
}
Declare it as a static attribute of a singleten class. Than you can access it with
$pdo = Singleton::instance()->getConnection();
Alternatively I can suggest taking a look at MArtin Fowler's relational database mapping pattern. It goes a step further, than centralizing ony the connection itself.
Alternatively Doctirne project has a complete implementation of that: www.doctrine-project.org
final class database {
private static $instance = NULL;
private $pdo; //added private variable for pdo
private function __construct() {
try {
$database = new PDO('mysql:host=127.0.0.1;dbname=coop1','root','');
$database->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
echo $e->getmessage();
die();
}
$this->pdo = $database; //saved the connection into the new variable
}
public static function getInstance() {
static $instance = null;
if (self::$instance === NULL) {
$instance = new database();
}
return $instance;
}
//added a function to get the connection itself
function getConnection(){
return $this->pdo;
}
}
So now you use it:
$pdo = database::getInstance()->getConnection();

How can I pass DB connection object from one class to another?

I'm trying to pass a PDO connection object from one class to another. But I'm not being very successfull. And I only want to instanciate only one PDO object.
With the help from dqhendricks and awm I managed to get the following solution working:
class Factory {
function createUser($id = NULL) {
return new User(Conn::get_conn(), $id);
}
function createApplication($id = NULL) {
return new User(Conn::get_conn(), $id);
}
}
class Conn {
private static $conn = NULL;
private function __construct() {}
private static function init() {
$conf = self::config();
try {
self::$conn = new PDO($conf['dsn'], $conf['user'], $conf['pass']);
}
catch (PDOException $e) {
echo $e->getMessage();
}
}
public static function get_conn() {
if (!self::$conn) { self::init(); }
return self::$conn;
}
private static function config($cfg_file = 'sl.config') {
$config = parse_ini_file('/../'.$cfg_file);
$conf = array();
$conf['user'] = $config['db_user'];
$conf['pass'] = $config['db_password'];
$conf['dsn'] = 'mysql:dbname='.$config['db_name'].';host='.$config['db_host'];
return $conf;
}
}
In my UserDAO class, I can now do this:
class UserDAO {
private $db;
private $id;
function UserDAO (&$db, $id) {
$this->db = &$db;
$this->id = &$id;
}
public function getRows($sql)
{
$result = $this->db->query($sql);
$row = $result->fetch(PDO::FETCH_ASSOC);
return $row;
}
function getUsers($limit = 10) {
$sql ="SELECT * FROM sl_store LIMIT $limit";
return $this->getRows($sql);
}
}
//My User class
class User extends UserDAO implements iUser {}
// And to test it working:
$user1 = Factory::createUser('5');
$user2 = Factory::createApplication('7');
How about defining an abstract class which gives you the PDO object on request?
E.g.
abstract class Db {
private static $x = null;
private static function init() {
try {
self::$x = new PDO(...);
} catch (PDOException $e) {
...
}
}
public static function getX() {
if (!self::$x) self::init();
return self::$x;
}
}
no need to have your class create an instance of itself if all you want is an instance of a different object back. maybe make a static method in Conn to return an instance of a db connection.
class Conn {
// prevent new statement
private __construct() {}
public static return_pdo() {
blah
blah
blah
return $db;
}
public static config($file) {
do stuff
}
}
then call statically
$pdo = Conn::return_pdo();
It's because new Conn() returns $Conn object, not the value from $Conn->Conn() method.
Try this:
class Conn{
function Conn() {
$db = new PDO($conf['dsn'], $conf['user'], $conf['pass']);
}
function get_db() {
return $this->db;
}
}
class Factory {
function createUser($id = NULL) {
$new_conn = new Conn();
$db = $new_conn->get_db();
}
}

php pdo mysql connect - confusing syntax problem

<?php
$mysql_host='mysql1.000webhost.com';
$mysql_dbname='a8130617_skola';
$mysql_username='something';
$mysql_password='something';
class mysql {
try{
public $db = new PDO("mysql:host=$mysql_host;dbname=$mysql_dbname",
$mysql_username, $mysql_password);
}
catch(PDOException $e){
echo $e->getMessage();
}
} //ERROR EXCLAMATION MARK HERE???
?>
why does netbeans 6.9.1 consider this to be false syntax?
many thanks
Do you know anything about OOP ?
Class should contain fields and/or methods. You just surrounded a piece of code with class{}. It is not programming.
Read about OOP in PHP - here is manual: http://php.net/manual/en/language.oop5.php
Read it for your own good.
Edit:
I know that following example can make you much lazy but I'll take a shoot and believe you will read more.
Example class for connections can look like:
class Mysql {
protected $_host;
protected $_dbname;
protected $_username;
protected $_password;
protected $_db;
public function __construct($host = null, $dbname = null, $username = null, $password = null)
{
$this->_host = $host;
$this->_dbname = $dbname;
$this->_username = $username;
$this->_password = $password;
}
public function connect()
{
try {
$this->_db = new PDO('mysql:host=' . $this->_host . ';dbname=' . $this->_dbname, $this->_username, $this->_password);
}
catch(PDOException $e){
echo $e->getMessage();
}
}
public function getDb()
{
return $this->db;
}
public function setHost($host)
{
$this->_host = $host;
return $this;
}
public function getHost()
{
return $this->_host;
}
public function setDbname($dbname)
{
$this->_dbname = $dbname;
return $this;
}
public function getDbname()
{
return $this->_dbname;
}
public function setUsername($username)
{
$this->_username = $username;
return $this;
}
public function getUsername()
{
return $this->_username;
}
public function setPassword($password)
{
$this->_password = $password;
return $this;
}
public function getPassword()
{
return $this->_password;
}
}
And example usage:
$mysql = new Mysql('mysql1.000webhost.com', 'a8130617_skola', 'something', 'something');
$mysql->connect();
try{
public $db = new PDO("mysql:host=$mysql_host;dbname=$mysql_dbname",
$mysql_username, $mysql_password);
}
catch(PDOException $e){
echo $e->getMessage();
}
Try catch blocks need to be inside a method. But going with that, not sure why you are wrapping this in a class? Your class is a wrapper for an already defined class.

Categories