PHP Singleton instantiation with String class name - php

Im building a small MVC system and i want my controllers to be Singletons. I made the base controller "Controller" a singleton and every other controller extends from that. My Router processes the request from the URL and grabs the controller string name.
This is where im getting the private constructor error because i am trying to do this:
class IndexController extends Controller {
//the "Index" part comes from the url
}
class Controller {
private $instance;
/**
* Initializes a new Singleton Controller
*/
private function __construct() {
}
/**
* Get the instance of the Controller
*/
public static function getInstance(){
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
}
$className = "Controller";
$inst = new $className; //here is where i get the error
$inst = $className::getInstance() //also fails
I have done my research and i stumbled upon this (http://www.php.net/manual/en/reflectionclass.newinstancewithoutconstructor.php), however I am not sure if that will work or is the best method if it does.

$inst = new $className; //here is where i get the error
This error is right, as the constructor is private.
$inst = $className::getInstance() //also fails
This error is also right, as this syntax is not allowed.
If you want your conrollers to be singletons, you can, but you need to "twist" the rules for that.
b.t.w
Why on earth would you want to do this?
Why not just use an existing MVC (you do not need the entire FW).
replace the self with static as this will reference the actual controller you try to instantiate and not the Controller class, as static references only the class it is written in.
Twisting the rules: You will need to instantiate your controllers through a factory (it is a pattern). Usually the front controller is used for that.

A couple things really in regards to errors in using the "pattern"
class Controller {
private static $instance;
/**
* Initializes a new Singleton Controller
*/
private function __construct() {
}
/**
* Get the instance of the Controller
*/
public static function getInstance(){
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
}
Note that the property is now static and the constructor is private as necessary for this anti-pattern.
Second your calling code should look like
$instance = Controller::getInstance();
You should never have to instantiate 'Controller' from the outside; the point of the pattern is to only allow access through Controller::getInstance()
That being said Singleton is little better than global state. Misko Hevery talks about it in this Google Clean Code Talk: Global State and Singleton. It is a really good video and explains far better than I can why Singletons are bad news. sourcemaking.com also has a good write-up on Singletons where they say that Singletons are unnecessary most of the time

class Controller {
/**
* Let the __construct method be private to prevent new instance though new.
*/
private function __construct() {}
/**
* Get the instance of the Controller
* Here use the lazy loading. (need php >= 5.3)
*/
public static function getInstance(){
if (null === static::$instance) {
static::$instance = new static();
}
return static::$instance;
}
}
class ControllerA extends Controller {
//You need an static property to hold the instance.
protected static $instance;
}
var_dump($a = ControllerA::getInstance());
var_dump($b = ControllerA::getInstance());
var_dump($a === $b);
If your Controller Name is a string, You can do like this:
$classname = "ControllerA";
call_user_func(array($classname, 'getInstance'));
call_user_func($classname .'::getInstance'); // As of 5.2.3

On this line:
$inst = $className::getInstance() //also fails
You are using the scope resolution operator. You should be using this '->' for access to object data members/methods.
$inst = $className->getInstance() //also fails
Otherwise, you need to use the scope resolution operator on the class rather than the object:
$inst = Controller::getInstance() //also fails
I do not know where you are getting the value off $className as a class. There is no class called IndexController.

Related

Singleton pattern returns different objects

So I am in a big mess here. I can say that my questions are few. I tried to make a singleton pattern but it returns me two different objects. This is what I made (saw in another post) and tried to test it.
class Singleton
{
private static $instance = [];
public function __construct(){}
public function __clone(){}
public function __wakeup(){
throw new Exception("Cannot unserialize singleton");
}
public static function getInstance()
{
$class = get_called_class();
if(!isset(self::$instance[$class])){
self::$instance[$class] = new static();
}
return self::$instance[$class];
}
}
class Dog extends Singleton
{
public $name;
public function __construct($name)
{
$this->name = $name;
}
}
$dog = new Dog("Jorko");
$dog2 = new Dog("Peshko");
echo $dog->name; // returns "Jorko"
echo $dog2->name; // returns "Pesho"
I thought the second object ($dog2) should not be created and I would get $dog again. And why are we creating empty __constructor in the class Singleton? Also, why are we using this get_called_class? I mean according to php manual Gets the name of the class the static method is called in.. That is what it returns but isn't new static. I thought that new static do the same thing. I am in a real mess. I searched around the web but can't get it clear in my head. Thank you a lot!
Actually this is not correct. To implement the singleton pattern correct the constructor has to be protected to prevent the creation of an object with the new operator. The magic methods __clone and __wakeup should be private to prevent cloning and unserializing of the object.
If you set the accessibility on these methods like i said, you can get an instance of the singleton object by using the static method getInstance() which is there for that very reason.

PHP maintain class state

I'd like to have a library class that maintains state across the same request. My use case is that I want to pass 'messages' to the class, and then call them at any time from a view. Messages can be added from any part of the application.
I had originally done this via static methods, which worked fine. However, as part of the lib, I also need to call __construct and __destruct(), which can't be done on a static class.
Here's a very simple example of what I am trying to do:
class Messages
{
private static $messages = array();
public function __construct()
{
// do something
}
public function __destruct()
{
// do something else
}
public static function add($message)
{
self::$messages[] = $message;
}
public static function get()
{
return self::$messages;
}
}
I can then add messages anywhere in my code by doing
Messages::add('a new message');
I'd like to avoid using static if at all possible (testability). I have looked at DI, but it doesn't seem appropriate, unless I'm missing something.
I could create a class (non-static) instead, but how do I then ensure that all messages are written to the same object - so that I can retrieve them all later?
What's the best way to tackle this?
I looks like you could benefit from using the Singleton pattern - it is designed for an object that must have only one instance throughout a request. Basically, you create a private constructor and a static method to retrieve the sole instance. Here is an example of a singleton that will do what you describe.
<?php
class Messages
{
private static $_instance;
private $_messages = array();
private function __construct() {
// Initialize
}
static public function instance() {
if (! self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
public function add_message( $msg ) {
$this->_messages[] = $message;
}
public function get_messages() {
return $this->_messages;
}
private function __destruct() {
// Tear-down
}
}
$my_messages = Messages::instance();
$my_messages->add_message( 'How now, brown cow?' );
// ...
$your_messages = Messages::instance();
$msgs = $your_messages->get_messages();
echo $your_messages[0]; // Prints, "How now, brown cow?"
Since the constructor is private, you can only create a Messages object from within a method of the object itself. Since you have a static method, instance(), you can create a new Messages instance from there. However, if an instance already exists, you want to return that instance.
Basically, a singleton is the gatekeeper to its own instance, and it stubbornly refuses to ever let more than one instance of itself exist.
Sounds like you are wanting to do a Singleton class. This will create an instance in one class and allow you to access that same instance in another class. Check out http://www.developertutorials.com/tutorials/php/php-singleton-design-pattern-050729-1050/ for more information.
How about making it a singleton class?
class Messages
{
// singleton instance of Messages
private static $instance;
public function __construct() { ... }
public static function getInstance()
{
if (!self::$instance)
{
self::$instance = new Messages();
}
return self::$instance;
}
}
This would ensure that all your messages get written to the same object, and also allow you to call __construct and __destruct
What you need is the Singleton pattern:
final class Singleton {
// static variable to store the instance
private static $instance = NULL;
// disable normal class constructing
private function __construct() {}
// instead of using the normal way to construct the class you'll use this method
public static function getInstance() {
if (NULL === self::$instance) {
self::$instance = new self;
}
return self::$instance;
}
// disable external cloning of the object
private function __clone() {}
}
// get the instance across some of your scripts
$singleton = Singleton::getInstance();
Sounds a bit like you want a singleton, although as an anti-pattern I'd avoid it.
You could do a full static class where every static member calls a self::_isBuilt(); method to do your construct elements. Destruct is a little trickier.
The best case for your needs might be a normal (non-static) class that you build right away and then access from a global... not super neat, but allows construct/destruct and members, and your statics to use $this which could be helpful. If you don't like the global variable, you could also wrap it in a method (a trick used in JS a fair bit) but it's not really any neater.
As a normal global class:
$myClass=new myClass();
//Access anywhere as:
globals['myClass']->myFunction(..);
Wrapped in a function
function my_class() {
static $var=null;
if ($var===null) $var=new myClass();
return $var;
}
//Access anywhere as:
my_class()->myFunction(..);

Access property of 'singleton' class PHP

I am not sure whether the technique I use is appropriate or not.
I have a class, singleton, with a subinstance like this:
final class Singleton {
public $subinstance;
private static $instance = NULL;
private function __construct() {
$this->subinstance = new subinstance();
}
public static function getInstance() {
if (NULL === self::$instance) {
self::$instance = new self;
}
return self::$instance;
}
private function __clone() {}
}
And now if I want to access the subinstance from outside the class in another class, I do:
$s = singleton::getInstance();
$s->subinstance->....
Is this the right way to do this?
And what happens when I do $s=singleton::getInstance();, does the entire singleton class gets copied into $s or is this more like a pointer?
What you are doing is fine, although in your example code I'm assuming you meant to write:
$s = Singleton::getInstance(); // with the S capitalized
When you call the getInstance method, the class is looking to see if a version of itself has already been instantiated. If it has, it will return a reference to that instance instead of creating an entirely new instance. If the instance has not been created yet, it will create the instance and then return a reference to it.
I'm not sure why sixeightzero has stated that you shouldn't instantiate a class in the constructor of your instance. You shouldn't experience any issues when doing so.
If you do $a = singleton, $a will be a reference to the singleton class. Any changes in $a will reflect in access by singleton:: etc.. (pointer)
Why are you doing a subinstance in the constructor? This can cause issues, and should create a method to handle the subinstance outside the constructor inside a protected method. What does your subinstance look like?

PHP Singleton extending class

I am new to OOP (PHP) and just met the design pattern - singleton.
I have found a DB class which uses mysqli (singleton class). I have added some custom methods to it (insert_id(), query(), fetch_result(), etc).
Then I created a new class called UserTools and I want to extend the database class to use the methods I've created previously (query(), fetch_result(), etc).
But I get this error:
Fatal error: Call to private Database::__construct() from invalid context in (...)
when I try to create instance of the new class (User Tools).
What should I do? Is it a right structure?
There are several way to achieve what you want.
One would be :
class UserTools {
private $db;
function __construct() {
$this->db = Database::db_connect();
}
function login() { /* ... */}
}
Although it would be better to directly pass the database instance to the constructor like this :
class UserTools {
private $db;
function __construct($db) {
$this->db = $db;
}
function login() { /* ... */}
}
// Usage
$userTools = new UserTools(Database::db_connect());
If you're really lazy you could just modify your database class and make the constructor public :
class Database {
/* ... */
public function __construct(){/* ... */}
/* ... */
}
class UserTools extends Database {/* ... */}
But I really discourage you to use the latter one. It's really bad code and it doesn't make sense in a logical point of view. Your UserTools class use a database instance. It is not a database.
It is my understanding that only protected and public methods and variables are inherited through extension, not private ones. Try changing your methods/variables from private to protected. public ones are visible to all.
For more information, See: PHP Visibility (Manual)
Edit
Understand the Singleton pattern. It is called 'singleton' because only one instance of a class is expected. Because of this, most classes implementing the singleton pattern define the constructor as private to restrict you from creating more than one.
To create an instance of a singleton, most classes define some kind of getInstance static method, which is public. This public method calls the private constructor, which probably sets flags indiciating that the class has been instantiated in order to prevent further attempts to instantiate the class. The getInstance method returns the results of calling the constructor, essentially the instance of the class.
You could write something like
class UserTools extends DB {
....
}
A quick example on inheritance in PHP:
class A {
public $a;
public function set_a($new_a) { $this->a = $new_a; return $this; }
public function get_a() { return $this->a; }
}
class B extends A {
public $b;
public function set_b($new_b) { $this->b = $new_b; return $this; }
public function get_b() { return $this->b; }
}
$objb = new B();
$objb->set_a("Some Value")->get_a(); //Some Value
The singleton pattern in most cases prevents instantiating the Singleton class by defining the constructor as private (ie private function __construct()).
So if you try to instantiate either your custom class or the original one that you're extending you will get the message above. You should either create a different class or define and use your function as static (eg public static function query($sql, $dbconnection)).
See http://php.net/manual/en/language.oop5.patterns.php

Registry pattern and lazy instantiation of registered objects

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

Categories