Syntax - accessing a class's property's method - php

I just upgraded my php form mysql to use mysqli in an object oriented approach. I have reason to believe that this code has bug in it. My goal is to use a singlton pattern to guarantee only one database connection per script execution. $db holds the database link.
Can someone verify the line
return $one->$db->query($query);
the syntax looks off.
class one
{
private static $single = NULL;
public $db = NULL;
public function __construct()
{
$this->db = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_DATABASE);
self::$single=1;
}
public static function make_one()
{
if(self::$single==NULL)
{
return new self();
}
}
}
/*database*/
class database
{
public function __construct()
{
one::make_one();
}
public static function arche_query($query)
{
return $one->$db->query($query);
}
}

Change it to
return one::make_one->db->query($query);
how ever your singleton pattern is not correct
A singleton pattern should create only one instance , in your case its not that case
class one
{
private static $_selfInstace;
public $db;// default is null so no need to assign
public function __construct()
{
$this->db = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_DATABASE);
}
public static function getInstance()
{
if( !(self::$_selfInstace instanceof self) ) {
self::$_selfInstace= new self();
}
return self::$_selfInstace;
}
}
class database
{
public function __construct()
{
}
public static function arche_query($query)
{
return one::getInstance()->db->query($query);
}
}

Related

Is die function accept only strings?

this code works:
if (isset($db->error)) {
echo $db->error;
}
This code in not working:
if (isset($db->error)) {
die($db->error);
}
This is my DB class:
class Db {
private $db,
$error;
public function __construct() {
return $this->db = new mysqli(DB_SERVER, DB_USER, DB_PASS, D_NAME);
if ($this->db->connect_error) {
$this->error = $this->db->connect_error;
}
}
}
"D_NAME" is wrong so an error appears but I didn't kill the page, content still appear after the error. Why? Thanks!
The if block in the constructor is never executed, because you are returning $this->db:
public function __construct() {
return $this->db = new mysqli(DB_SERVER, DB_USER, DB_PASS, D_NAME);
// the lines after return will never be executed!
}
This is the first reason why the $db->error is unset.
The second reason is that the $error member is private, which means that you are not allowed to access this property directly. So you should make it accessible in one of the following ways (at least):
make it public;
implement the __get and __isset magic methods;
implement a getter method.
Using public $error
class Db {
private $db;
public $error;
public function __construct() {
$this->db = new mysqli('localhost', 'sss3', 'a4J1uQzQCasD', 's3_small');
if ($this->db->connect_error) {
$this->error = $this->db->connect_error;
}
return $this->db;
}
}
$db = new Db;
if (isset($db->error)) {
die($db->error);
}
echo 'xxx', PHP_EOL;
Using __isset and __get magic methods
class Db {
private $db;
private $error;
public function __construct() {
$this->db = new mysqli('localhost', 'sss3', 'a4J1uQzQCasD', 's3_small');
if ($this->db->connect_error) {
$this->error = $this->db->connect_error;
}
return $this->db;
}
public function __get($key) {
if ($key === 'error') {
return $this->error;
}
}
public function __isset($key) {
if ($key === 'error') {
return isset($this->error);
}
}
}
$db = new Db;
if (isset($db->error)) {
die($db->error);
}
echo 'xxx', PHP_EOL;
Implementing a getter method
A getter method is just a method returning value of a private member. In our case it is $error. So you might leave it private, but add a method to access its value. For instance:
public function getError() {
return $this->error;
}

Creating a globally accessible MySQLi object

I have multiple classes that use static methods. These functions connect to the database using
$mysqli = new mysqli(DB_SERVER, DB_USER, DB_PASS, DB_NAME);
where the constants DB_SERVER, DB_USER, DB_PASS, DB_NAME are database variables defined in a globally accessible file. Recently, my site started becoming slow and after profiling the script I realized that the call to create the object($mysqli) was causing this problem.
Most of my classes extend from mysqli such that
public function __construct($user_id) {
parent::__construct(DB_SERVER, DB_USER, DB_PASS, DB_NAME);
$this->retrieve_user_details($user_id);
$this->check_user_account_type();
}
It is to my understanding that static methods DO NOT use the __construct method.
Could someone guide me on how I can create the $mysqli object once such that it can be accessed by all static methods that require it.
Here is one approach:
Create a singleton class, that can be accessed statically from anywhere.
class DBConnector {
private static $instance ;
public function __construct($host, $user, $password, $db){
if (self::$instance){
exit("Instance on DBConnection already exists.") ;
}
}
public static function getInstance(){
if (!self::$instance){
self::$instance = new DBConnector(a,b,c,d) ;
}
return $instance ;
}
}
An example would be:
$mysqli = DBConnector::getInstance() ;
Hovewer I suggest using another solution as well:
$mysqli = new MySQLi(a,b,c,d) ;
Then you could pass that object to other classes (constructor)
class Shop {
private $mysqli ;
public function __construct(MySQLi $mysqli){
$this->mysqli = $mysqli ;
}
}
$show = new Shop($mysqli) ;
To elaborate on a mysqli singleton:
define('SERVER', 'localhost');
define('USERNAME', 'root');
define('PASSWORD', 'password');
define('DATABASE', 'databaseName');
class mysqliSingleton
{
private static $instance;
private $connection;
private function __construct()
{
$this->connection = new mysqli(SERVER,USERNAME,PASSWORD,DATABASE);
}
public static function init()
{
if(is_null(self::$instance))
{
self::$instance = new mysqliSingleton();
}
return self::$instance;
}
public function __call($name, $args)
{
if(method_exists($this->connection, $name))
{
return call_user_func_array(array($this->connection, $name), $args);
} else {
trigger_error('Unknown Method ' . $name . '()', E_USER_WARNING);
return false;
}
}
}
You can then request the database connection by calling:
$db = mysqliSingleton::init();
You can then retrieve the database connection in your own objects:
class yourClass
{
protected $db;
public function __construct()
{
$this->db = mysqliSingleton::init();
}
}
This is the shortest version I could come up with for Bootstrap 3.
$(document).ready(function() {
if (hash = window.location.hash) {
$('.nav-tabs a[href="' + hash + '"]').tab('show');
}
});

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.

Singleton pattern in php

class SingleTon
{
private static $instance;
private function __construct()
{
}
public function getInstance() {
if($instance === null) {
$instance = new SingleTon();
}
return $instance;
}
}
The above code depicts Singleton pattern from this article. http://www.hiteshagrawal.com/php/singleton-class-in-php-5
I did not understand one thing. I load this class in my project, but how would I ever create an object of Singleton initially. Will I call like this Singelton :: getInstance()
Can anyone show me an Singleton class where database connection is established?
An example of how you would implement a Singleton pattern for a database class can be seen below:
class Database implements Singleton {
private static $instance;
private $pdo;
private function __construct() {
$this->pdo = new PDO(
"mysql:host=localhost;dbname=database",
"user",
"password"
);
}
public static function getInstance() {
if(self::$instance === null) {
self::$instance = new Database();
}
return self::$instance->pdo;
}
}
You would make use of the class in the following manner:
$db = Database::getInstance();
// $db is now an instance of PDO
$db->prepare("SELECT ...");
// ...
$db = Database::getInstance();
// $db is the same instance as before
And for reference, the Singleton interface would look like:
interface Singleton {
public static function getInstance();
}
Yes, you have to call using
SingleTon::getInstance();
The first time it will test the private var $instance which is null and so the script will run $instance = new SingleTon();.
For a database class it's the same thing. This is an extract of a class which I use in Zend Framework:
class Application_Model_Database
{
/**
*
* #var Zend_Db_Adapter_Abstract
*/
private static $Db = NULL;
/**
*
* #return Zend_Db_Adapter_Abstract
*/
public static function getDb()
{
if (self::$Db === NULL)
self::$Db = Zend_Db_Table::getDefaultAdapter();
return self::$Db;
}
}
Note: The pattern is Singleton, not SingleTon.
A few corrections to your code. You need to ensure that the getInstance method is 'static', meaning it's a class method not an instance method. You also need to reference the attribute through the 'self' keyword.
Though it's typically not done, you should also override the "__clone()" method, which short circuits cloning of instance.
<?
class Singleton
{
private static $_instance;
private function __construct() { }
private final function __clone() { }
public static function getInstance() {
if(self::$_instance === null) {
self::$_instance = new Singleton();
}
return self::$_instance;
}
}
?>
$mySingleton = Singleton::getInstance();
One thing to not is that if you plan on doing unit testing, using the singleton pattern will cause you some difficulties. See http://sebastian-bergmann.de/archives/882-Testing-Code-That-Uses-Singletons.html
class Database{
private static $link=NULL;
private static $getInitial=NULL;
public static function getInitial() {
if (self::$getInitial == null)
self::$getInitial = new Database();
return self::$getInitial;
}
public function __construct($server = 'localhost', $username = 'root', $password ='tabsquare123', $database = 'cloud_storage') {
self::$link = mysql_connect($server, $username, $password);
mysql_select_db($database,self::$link);
mysql_query("SET CHARACTER SET utf8", self::$link);
mysql_query("SET NAMES 'utf8'", self::$link);
return self::$link;
}
function __destruct(){
mysql_close(self::$link);
}
}

How do I throw an error for my singleton class?

This is the singleton pattern also named as the singleton class. Its goal is to allow only one object of type singleton. If there is already one and I call it, I'd like it to error out in some way. This won't happen in production but in development. Is there a better way then just saying echo echo "Error:only one connection";
class singleton
{
protected static $_db_pointer = NULL;
private function __construct()
{
$this->_db_pointer = mysql_connect(DB_HOST, DB_USER, DB_PASS);
mysql_select_db(DB_DATABASE);
}
public static function get_instance()
{
if(self::$_db_pointer == NULL)
{
return new self();
}
else
{
echo "Error:only one connection";
}
}
}
Exceptions usually are better.
else
{
throw new Exception("Error:only one connection");
}
You can also use "LogicException", "RuntimeException", and a few others.
Further reading:
http://www.php.net/manual/en/language.exceptions.php
Another approach with singleton class is just to return the object instead of creating a new instance if one exists.
You haven't implemented the singleton pattern correctly. Had you done so, the error condition to which you refer could not exist.
Combining the PHP documentation's singleton example and the original code gives:
class singleton
{
// Hold an instance of the class
private static $instance;
private static $db_pointer;
// A private constructor; prevents direct creation of object
private function __construct() {
$this->_db_pointer = mysql_connect(DB_HOST, DB_USER, DB_PASS);
mysql_select_db(DB_DATABASE);
}
// The singleton method
public static function get_instance()
{
if (!isset(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c;
}
return self::$instance;
}
public function getDbPointer() {
return self::$db_pointer;
}
// Prevent users to clone the instance
public function __clone() {
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
}

Categories