Singleton syntax in PHP code - php

I understand the singleton pattern, but I don't understand the following syntax:
public static function get()
{
static $db = null;
if ( $db == null )
$db = new DatabaseConnection();
return $db;
}
private function __construct()
{
$dsn = 'mysql://root:password#localhost/photos';
$this->_handle =& DB::Connect( $dsn, array() );
}
Why every time we call DatabaseConnection::get() we could ge the same singleton object? Because the code read from me will like:
static $db = null; //set $db object to be null
if($db==null) // $db is null at the moment every time because we just set it to be null
// call the private constructor every time we call get() *
$db = new DatabaseConnection();
return $db; // return the created
Then how the get() function could always return a same object?
I am new to Php, most of the syntax to me will read like java, please any one could explain this to me?
Also is there any instructions/tutorial that I could read for understanding more syntax sugar like:
$array_object[] = $added_item

Try this inside your class:
private static $db;
public static function get(){
if(!self::$db){
self::$db = new DatabaseConnection();
}
return self::$db;
}

Related

Assign a public static function's return value to a private variable

There are two classes:
class Db {
public static function getConnection () {
/*Initialize parameters*/
$db = new PDO (...);
return $db;
}
}
Class Db initializes and returns a PDO object.
Then I want to do following in another class:
class User {
private $db = Db::getConnection();
....
}
Why am I getting an error here:
private $db = Db::getConnection();
Without knowing the error, it's hard to say, but I'd guess is because you can't do that there, try this.
class User {
private $db = null;
function __construct(){
$this->db = Db::getConnection();
}
public function getFriends(){
return $this->db->query('SELECT * FROM friends');
}
}

Singleton database class method

I'm trying to write a query() method for a singleton database class. I have this but it ain't flying just yet and was looking for some inspiration.
<?php
class Database
{
static private $instance = null;
protected $mysqli;
static public function getInstance()
{
if (null === self::$instance) {
self::$instance = new self;
}
return self::$instance;
}
private function __construct(){
if(!$this->mysqli = new mysqli('localhost','user','pass','db'))
throw new Exception('Error - Database connection');
}
public function query($query) {
while ($this->mysqli->query($query))
{
$row = $this->mysqli->fetch_assoc();
}
return $row; // loop through array
}
private function __clone(){}
}
?>
I'm not entirely sure if I'm going down the correct road. Will mysqli work in this context?
For instance the Mysqli class already has a query() method as part of its class. I'm introducing namespace clashes here?
My query method would handle any sort of SQL statement ie.
Example client code:
$DB = Database::getInstance();
$DB->query("SELECT * FROM t");
$DB->query("DELETE FROM t WHERE id=2");
$DB->query("UPDATE u SET col = 'random' WHERE id=4");

mysqli constructor returns null

I am trying to write a db util class using the singleton pattern. My problem is that the "connection" object is always null. The connection settings are correct. What could i be doing wrong ? Also, i am relatively new to php development. What method should i use to figure out what's wrong ? Code follows.
class DBUtil {
public $connection = NULL; //mysqli_connection object
private static $instance = NULL;
private function _constructor($conn){
//$this->connection = mysqli_connect(TagMetroConfiguration::getConfigurationValueFor("db_servser_name"), TagMetroConfiguration::getConfigurationValueFor("db_username"), TagMetroConfiguration::getConfigurationValueFor("db_password"), TagMetroConfiguration::getConfigurationValueFor("db_name"));
$this->connection = new mysqli("localhost", "root", "toor", "testdb");
}
public static function getInstance(){
if(DBUtil::$instance == NULL){
try{
DBUtil::$instance = new DBUtil();
}catch(Exception $ex){
throw new Exception("Unable to create DB Instance");
}
}
return DBUtil::$instance;
}
}
Your constructor function should be named __construct (notice two underscores).
Also, in your constructor, you have one parameter, $conn. When you call new DBUtil(), you are not providing that input parameter, so perhaps it's calling the default contructor, not your custom one.
If you want the input parameter $conn to be optional, try __construct($conn = null).
Or try calling it as new DBUtil(null).
private function _constructor($conn) ??
should this be
private function __construct($conn)
There should be two underscores __ (__construct).
You should do like this :
class DBUtil {
private static $instance;
private function _construct(){
$this->$instance = new mysqli("localhost", "root", "toor", "testdb");
}
public static function getInstance(){
if(!isset(self::$instance){
try{
self::$instance = new DBUtil();
}catch(Exception $ex){
throw new Exception("Unable to create DB Instance");
}
}
return self::$instance;
}

PHP Singleton Database Query

In PHP, I have following Singleton Database Class:
class Database
{
private static $instance;
private function __construct()
{
self::$instance = new mysqli('localhost', 'root', 'Matthias', 'financecontrol', '3307');
if (!self::$instance) {
throw new Exception('Could not connect to database in function __construct.');
}
}
public static function getInstance()
{
if (!self::$instance) {
self::$instance = new Database();
}
return self::$instance;
}
}
Whenever I try to perform a query on the database in another PHP file, for example to check whether a user already exists:
function userExists($username)
{
try {
$connection = Database::getInstance();
$result = $connection->query("select * from user where username='$username'");
if (!$result) {
throw new Exception("Connection to database failed in function userExists.");
}
if ($result->num_rows > 0) {
return true;
} else {
return false;
}
} catch (Exception $ex) {
$errorPager = new ErrorpageGenerator();
$errorPager->generateErrorPage($ex->getMessage());
return false;
}
}
I get an error message "PHP Fatal error: Call to undefined method Database::query() in User.php on line 44"
I've tried adding a query function in the Database class, but that did not seem to fix the problem. Any ideas? Thanks
You have to add this method of course. But you cannot assign Database() and the mySQLi object to m_pInstance
so do:
class Database
{
private static $conn;
// ...
public function __construct()
{
self::$conn = new mysqli('localhost', 'root', 'root', 'database', '3307');
//...
and then
public function query($sql)
{
return self::$conn->query($sql);
// or
return mysqli_query(self::$conn, $sql);
}
EDIT
Working code:
class Database
{
private static $instance = null;
private static $conn;
private function __construct()
{
self::$conn = new mysqli('localhost', 'root', 'root', 'database', '3307');
}
public static function getInstance()
{
if (self::$instance == null) {
self::$instance = new Database();
}
return self::$instance;
}
public function query($sql)
{
return self::$conn->query($sql);
}
}
You get this error, because Database::$m_pInstance is contains an instance of Database class and not instance of MySQLi. You have created a "conflict" between to parts of the code:
public static function getInstance()
{
if (!self::$m_pInstance) {
self::$m_pInstance = new Database(); // << PROBLEM
}
return self::$m_pInstance;
}
Which overrides what your constructor does:
private function __construct()
{
self::$m_pInstance = new mysqli( /* .. */ ); // PROBLEM
if (!self::$m_pInstance) {
throw new Exception('Could not .. blah');
}
else {
return self::$m_pInstance;
}
}
Even though the constructor assigns self::$m_pInstance the instance of MySQLi object, it gets overridden by self::$instance = new Database(); right after.
Also, in php __constuct() method should not return, ever.
That said, i think is should warn you that singleton is considered to be an anti-patterns, and should be avoided. Your code also has the unintended side-effect, forcing you to have only one database (not connection, the database) available per application.
You might benefit from watching few lectures:
Advanced OO Patterns (slides)
Global State and Singletons
Don't Look For Things!
Your code does not look right.
first, you assign $m_pInstance a new Database instance. But then, in the constructor, you assign it a new mysqli instance. I am unsure how php handles this case, but it seems that it treats it as Database object as indicated by your error message. The Database class however does not have a query method.
So the solution would be to save the mysqli object in a different field and add getters and setters for it or delegate the methods to it.

Start work with PHP OOP

I now learn PHP OOP and I want to get yours tips. I create DB connection class, is this okay?
How use "Database" class in another class? Always use "extends"?
Thanks
<?php
//Config
$db_user = 'root';
$db_pass = '';
$db_host = 'localhost';
$db_name = 'test';
class Database
{
private $Database;
private static $instance;
public static function instance()
{
if ( !self::$instance )
self::$instance = new Database();
return self::$instance;
}
public function connect($host, $user, $password, $name)
{
$this->db_link = mysql_connect($host, $user, $password);
mysql_set_charset('utf8');
mysql_select_db($name, $this->db_link);
}
public function query($query)
{
$sql = mysql_query($query);
$row = mysql_fetch_array($sql);
return $row;
}
}
class Book extends Database
{
public function getData2()
{
$sql = $this->query('SELECT * FROM users WHERE price = "7"');
return $sql['name'];
}
}
$db = Database::instance();
$db->connect($db_host, $db_user, $db_pass, $db_name);
$b = new Book();
$res = $b->getData2();
print_r($res);
?>
You can extends the database class but it is not what I suggest.
You could also use the keyword global inside the function where you actually need database to let the function get the database instance from outside; but still some people get nervous about global keyword.
You could pass the instance of the database class as argument of constructor of the class where you need database, in this way you will be able to call db methods with a simple chain: $this->db->connect();
As björn states, a book is not a database, wouldn't recommend extend.
One approach would be to on object initialization of book, pass the reference to the db-layer/object..
$myDb = new dbLayer($settings);
$myBook = new book($myDb);
$a = $myBook->getAllData($someParameter);
in the constructor of book you save the reference to the dblayer...
class book {
var $dbTier;
__constructor($db) {
$this->dbTier = $db;
...
regards,
//t
You can do something like this, this should be easy to understand
class User{
private $db;
public function __construct($db){
$this->db = $db;
}
}
The $db in the constructor parameter would be your database connection and required fom another file. All any how you get to it but not in the class.
require 'file from where you have your database';
$user = new User($db);
Anytime you like to user the database to make a query, you just reference it like below
$this->db->query();
You would not use extends here ideally unless Book is a subclass of Database. You would do something like:
class Book
{
var $db;
function __construct() {
$this->db = Database::instance();
}
}
Then the book class would use the instance of the database object and you can always access it with $this->db inside Book.

Categories