So currently my class DATABASE uses a singleton for a connection and is called in the constructor of my class SQL. I have 4 other classes that extend class SQL for access to its methods. The problem is, the children instantiate each other in some cases so I'm afraid I'm creating multiple class SQL objects because they call their parent constructor by default, aka class SQL. I read about dependency injection, but no clear how to implement it in my situation so this is what I was thinking.
Have all classes extend class DATABASE and make class SQL methods static.
But then I would have to call the singleton connection in class DATABASE, on its own class as so.
class DATABASE {
function __construct() {
self::getInstance();
/// or DATABASE::getInstance ( im not quite positive which way )
}
public static function getInstance() {
if (self::$instance == false) {
self::$instance = new DATABASEMANAGER();
}
return self::$instance;
}
}
I figure this way, since all classes extend class DATABASE, and instantiate each other, I know I am not creating multiple objects.
I hope this makes sense and I can elaborate more if you need me to, but does this make since as an approach to my problem?
I guess you building your class other way around, this approach is more consistent in my opinion.
class DATABASE extends DATABASEMANAGER
{
static $instance;
private function __construct()
{
parent::__construct();
}
public static function getInstance()
{
if (empty(self::$instance))
{
self::$instance = new self();
}
return self::$instance;
}
}
Usage:
class Blog
{
public function __construct()
{
$this->database = DATABASE::getInstance();
}
public function getRecord($id)
{
$result = $this->database->query("SELECT * FROM blog WHERE id='{$id}'");
//or
$result = DATABASE::getInstance()->query("SELECT * FROM blog WHERE id='{$id}'");
//other actions...
}
}
Related
Lets say i have a singleton class with the sole purpose of creating singletons:
class singleton {
public static function getInstance() {
static $instance = null;
if($instance === null) {
$instance = new self;
}
return $instance;
}
}
And a custom database class extending the default one:
class database extends mysqli {
// obvious stuff
}
I now want to be able to have the database class being a children of both, the singleton (for the singleton creation) and the mysqli-class. Basically something like:
class database extends singleton {}
class database extends mysqli {}
According to my research, this is not possible in PHP.
What I'm trying to achieve is, having another method called getInstance() in the database class (so, this method is present in the classes "database" and "singleton", which then first calls the parent constructer (that creates the singleton) and then returns to the child to continue with custom stuff for the corresponding class. Like this:
class singleton {
public static function getInstance() {
static $instance = null;
if($instance === null) {
$instance = new self;
}
return $instance;
}
}
class database extends singleton {}
class database extends mysqli {
public static function getInstance() {
$instance = parent::getInstance();
// Custom code
return $instance;
}
}
Is that somehow possible? I thought about traits, but you cannot call them as parents.
I am trying out a MVC concept where the main model for a database stems or trees off other models. I wanted to have a main database sort of model which does the connecting and queries. Then, other models are built to support the controller. Ie, a product model can be extended off the main database model to then query rather than using dependency injection.
My current ideology and attempt looks like this for the main database model:
namespace Portfolio\Application;
abstract class DriverModel {
private static $driver;
private $entity;
private function __construct() {
// Connection to the PDO will be done in here
}
private function __clone() {}
public static function getInstance() {
if(self::$driver)
return self::$driver;
self::$driver = new self();
return self::$driver;
}
protected function q($sql, $values = []) {
$stmt = $this->entity->Prepare($sql);
$stmt->execute($values);
return $stmt;
}
}
Then my example profile controller would look something like this (having the methods to use the main database to run queries):
class ProfileModel extends DriverModel {
public function doSomeQ() {
$this->q('SELECT fname FROM users WHERE id = ?', [(int)1]);
}
}
However, When I execute this line of code:
print_r(ProfileModel::getInstance()->doSomeQ());
I am left with this error: (which makes sense.)
Uncaught Error: Cannot instantiate abstract class.
I then remove the abstract attribute from the class (class DriverModel) but now, the instance I am receiving is the instance from the parent class meaning if I do a print_r() on the getInstance() method to the ProfileModel, there is no doSomeQ() method.
Any help on achieving this methodology would be helpful.
You have to use get_called_class() method instead of new self();
http://php.net/manual/en/function.get-called-class.php
Attached you can find sample who show your expected behaviour
class Main {
public static function getInstance() {
$class = get_called_class();
return new $class();
}
}
class Foo extends Main{
}
var_dump(Foo::getInstance()); // Output Foo object
Consider the following code below, I've been thought by Lynda.com
to create a database class like this, my question is why not create
a static method for the database entirely instead of storing an
instance into a static property?
<?php
class Database {
private $conn;
private static $init;
public function __construct() {
$this->conn = new mysqli('localhost','root','root','mydb');
}
public static function getInstance() {
self::$init = new self();
return self::$init;
}
}
$db = Database::getInstance();
?>
If you want to use singleton you should to protect __construct()
class DB
{
private static $instance;
private function __construct($args)
{
// do some
}
public static function getInstance()
{
// get instance
}
}
$query = 'SELECT etc...';
$stmt = DB::getInstance()->prepare($query);
I use this pattern in DB class. But if you have more than 1 connection you should NOT! use singleton.
My guess is that code you posted was intended to be the following because it looks like it was intended to be a singleton. I've only changed the getInstance() method.
class Database {
private $conn;
private static $init;
public function __construct() {
$this->conn = new mysqli('localhost','root','root','mydb');
}
public static function getInstance() {
if (is_null(self::$init)) {
self::$init = new self();
}
return self::$init;
}
}
$db = Database::getInstance();
I think this should clear up the confusion of why a static instance variable is used.
If this wasn't intended to be a singleton, then your question of "why didn't they just use a static method" should have the answer "they should have".
Just to clarify, $db is a Database object, which is instantiated by calling static method getInstance().
why not create a static method for the database entirely?
A static method is defined inside a class, however it can be called without having to instantiate the class. In other words, a static method belongs to the class, since in can be called without instantiating an object.
You can add methods to the Database class to interact with the database as you deem necessary.
Let's imagine that we have Registry pattern...
<?php
class Registry
{
private static $objects = array();
private static $instance = null;
public static function getInstance() {
if (self::$instance == null) {
self::$instance = new Registry();
}
return self::$instance;
}
protected function _get($key) {
return ($this->objects[$key]) ? $this->objects[$key] : null;
}
protected function _set($key, $val) {
$this->objects[$key] = $val;
}
public static function get($key) {
return self::getInstance()->_get($key);
}
public static function set($key, $object) {
return self::getInstance()->_set($key, $object);
}
}
?>
Using this realization is really easy...
<?
Registry::set('db', $db_client);
Registry::set('redis', $redis_client);
//Using registered objects is really easy
Registry::get('db')->query("...");
Registry::get('redis')->get("...");
?>
But as you can see, we're adding instances into registry even if we don't need them (yes, it's all about performance).
So, the question is... How to modify Registry pattern to be able to do lazy instantiation?
Here is what I'm looking for...
<?
class Registry
{
private static $objects = array();
private static $instance = null;
public static function getInstance() {
if (self::$instance == null) {
self::$instance = new Registry();
}
return self::$instance;
}
protected function _db() {
if (!$this->objects['db']) {
$this->objects['db'] = new DatabaseAdapter(DB_HOST, DB_NAME, DB_USER, DB_PASSWORD);
}
return $this->objects['db'];
}
protected function _redis() {
if (!$this->objects['redis']) {
$this->objects['redis'] = new Redis(REDIS_HOST, REDIS_DB, REDIS_USER, REDIS_PASSWORD);
}
return $this->objects['redis'];
}
public static function db() {
return self::getInstance()->_db();
}
public static function redis() {
return self::getInstance()->_redis();
}
}
?>
As you can see, DatabaseAdapter() or Redis() will be created only in we'll request them. Everything seems to be ok, but as you can see it's not a standalone class because _db(), _redis() methods contains connection constants etc.
How to avoid it? How can I define registry method within registry class to separate Registy class and objects inside it?
I'm really sorry about my English, but I hope it is clear for you.
Thank you.
PS: All code above was written 1 min. ago and wasn't tested.
If you use global constants you will always have a dependency on the global scope. It doesnt matter where it is. Also, even if you do not use constants, you still have the dependency on the Database class inside the Registry. If you want to dissolve those dependencies, you could use Factory methods on the to be created classes:
public function get($service)
{
if( !this->_data[$service] ) {
// requires PHP 5.2.3
this->_data[$service] = call_user_func($service .'::create');
}
return this->_data[$service];
}
So if you do get('DB'), the code would try to call the static DB::create() method inside the class you intend to create. But like I said, if you use global Constants for the configuration, you would just move the problem into another class.
Your db class could look like this:
class DB
{
protected static $_config;
public static setConfig(array $config)
{
self::_config = $config;
}
public static create()
{
return new self(
self::config['host'],
self::config['db'],
self::config['user'],
self::config['pass']);
}
}
The configuration can be stored inside an external configuration file, which you load and set to the DB class during bootstrap, e.g.
DB::setConfig(parse_ini_file('/path/to/db-config.ini'));
The disadvantage of this is, you have to add create() methods all over the place and all classes must be able to store their own configuration. You could centralize these responsibilities into a Builder pattern. But if you do this, you are half way to implementing an IoC Container anyways, so check out the following resources:
Fabien Potencier: What is Dependency Injection
Martin Fowler: Inversion of Control Containers and the Dependency Injection pattern
Design pattern – Inversion of control and Dependency injection
Note: You are using a "static" modifier for $objects - as you are working with an instance, this is probaby not necessary.
How can I define registry method within registry class to separate Registy class and objects inside it?
They are always separate: Each object inside the registry class is just a reference to the (independent) object. But if this question is about including the appropriate class definition (?) you may use the class_exists() function to load the class as soon as required.
BurninLeo
I am going to use singleton classes to manage both DB connections and references to application settings.
It seems a little messy to have to use the following code in every method in order to access the db class.
$db = DB::getInstance();
Is there a more efficient way of going about it?
Any advice appreciated.
Thanks
I often use the Registry pattern, where this behavior occurs as well. I always set a instance variable in the constructor of my models to point to the Registry entry;
class Registry {
private static $_instance;
private $_registry;
private function __construct() {
$_registry = array();
}
public static function getInstance() {
if (!Registry::$_instance) {
Registry::$_instance = new Registry();
}
return Registry::$_instance;
}
public function add($key, &$entry) {
$this->_registry[$key] = &$entry;
}
public function &get($key) {
return $this->_registry[$key];
}
public function has($key) {
return ($this->get($key) !== null);
}
}
Model example;
class MyModel {
private $_db;
public function __construct() {
$this->_db = Registry::getInstance()->get('dbKey');
}
/* Every function has now access to the DAL */
}
Instantiation example;
$dal = new Db(...);
Registry::getInstance()->add('dbKey', $dal);
...
$model = new MyModel();
$model->doDbStuff();
Another approach is to always pass the reference as a parameter to each constructor.
Of course I only use this behavior when most of the methods in my model use the reference, if only a few (one or two) methods have use of the reference, I call the Registry/Singleton like you showed.
It is not messy. This is an intended behavior of Singletons. And, actually, this is just one line of code. Do you wish to make it even more compact? :)
My preferred method is to create a Base class which all the classes that need db access descend from. Base calls the singleton(s) in its constructor. All its children call their parent constructor. e.g.:
class Base {
protected $db;
public function __construct(){
$this->db = DB::getInstance();
}
}
class Achild extends Base {
protected $var1;
public function __construct($arg){
parent::__construct();
$this->var1=$arg;
}
}
I know what you mean... hate that ::getInstance() stuff! So go and use static methods:
class DB {
private static $db;
public static function getInstance() {
if(!self::$db) {
self::$db = new DBconnector();
}
}
public static function query($query) {
return self::$db->query($query);
}
}
Usage is much nicer:
$result = DB::query('SELECT whatever;');
And if you use PHP 5.3 you can write a __callStatic similar to this, to forward all the method calls to the object:
public static function __callStatic($method, $args) {
call_user_func_array(array(self::$db, $method), $args);
}
And to make me happy, add an __autoloader so that you can access DB without any worries any time!