PHP class extends Singleton pattern - php

class singleton:
class Singleton
{
private static $_myself;
private function __construct(){}
public static function getInstance()
{
if(!isset(self::$_myself))
{
$obj = __CLASS__;
self::$_myself = new $obj;
}
return self::$_myself;
}
}
my class:
class MyApp extends Singleton
{
public function show()
{
echo 'show';
}
}
MyApp::getInstance()->show();
but not working, this error:
Call to undefined method Singleton::show()
somebody can help me?

Because you're returning a Singleton class (as you can see by your error), but should be returning a MyApp class. You can do this by using the late static binding method get_called_class() introduced in PHP 5.3:
public static function getInstance()
{
if(!isset(self::$_myself))
{
//__CLASS__ = Singleton | get_called_class() = MyApp
$obj = get_called_class();
self::$_myself = new $obj;
}
return self::$_myself;
}

self returns the actual class instance (Singleton in this case), so there is no method show. But you could use static instead of self (Differences) and change $_myself from private to protected so it is accessible in child classes.
class Singleton
{
protected static $_myself;
private function __construct(){}
public static function getInstance()
{
if(!isset(static::$_myself))
{
static::$_myself = new static;
}
return static::$_myself;
}
}

The problem is in
$obj = __CLASS__;
self::$_myself = new $obj;
You create a new instance of the class Singleton, not of the class MyApp, so the method is not available.
Now h2ooooooo was faster with his answer than I edited, see his answer regarding what to put instead of __CLASS__.

Related

How to get parent class instance?

I have two classes:
Singleton.php
namespace Core\Common;
class Singleton
{
protected static $_instance;
private function __construct(){}
private function __clone(){}
public static function getInstance() {
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
}
Config.php
namespace Core;
class Config extends Common\Singleton
{
private $configStorage = array();
public function setConfig($configKey, $configValue)
{
$this->configStorage[$configKey] = $configValue;
}
public function getConfig($configKey)
{
return $this->configStorage[$configKey];
}
}
my index.php
require_once 'common\Singleton.php';
require_once 'Config.php';
$config = \Core\Config::getInstance();
$config->setConfig('host', 'localhost');
but got the error: "Call to undefined method Core\Common\Singleton::setConfig()"
So as i can see getInstance() return me Singleton class instance, but not Config, how i can return Config instance from Singleton?
You can change your getInstance to this:
public static function getInstance() {
if (!isset(static::$_instance)) {
static::$_instance = new static;
}
return static::$_instance;
}
The difference between self and static is highlighted here:
self refers to the same class whose method the new operation takes place in.
static in PHP 5.3's late static bindings refers to whatever class in the hierarchy which you call the method on.
So it means that is bounded dynamically to the extending class, hence new static in your case refers to the Config class, using self will always statically refers to the Singleton class.
Working example here.

Getting class name from static function in abstract class

I have an abstract class that has a number of static functions (which return a new instance of itself by using new static($args) which works fine), but I can't work out how to get the class name. I am trying to avoid putting
protected static $cn = __CLASS__;
but if unavoidable, then its not the end of the world
abstract class ExtendableObject {
static function getObject() {
return new static($data);
}
static function getSearcher() {
return new ExtendableObjectFinder(/* CLASS NAME CLASS */);
}
}
class ExtendableObjectFinder {
private $cn;
function __construct($className) {
$this->cn = $className;
}
function where($where) { ... }
function fetch() { ... }
}
To get the name of the class you can use get_class and pass $this.
Alternatively, there is get_called_class which you can use within static methods.
You don't need to use the class name explicitly, you can use self.
class SomeClass {
private static $instance;
public static function getInstance() {
if (self::$instance) {
// ...
}
}
}
CodePad.

Instance as a static class property

Is it possible to declare an instance of a class as a property in PHP?
Basically what I want to achieve is:
abstract class ClassA()
{
static $property = new ClassB();
}
Well, I know I can't do that, but is there any workaround beside always doing something like this:
if (!isset(ClassA::$property)) ClassA::$property = new ClassB();
you can use a singleton like implementation:
<?php
class ClassA {
private static $instance;
public static function getInstance() {
if (!isset(self::$instance)) {
self::$instance = new ClassB();
}
return self::$instance;
}
}
?>
then you can reference the instance with:
ClassA::getInstance()->someClassBMethod();
An alternative solution, a static constructor, is something along the lines of
<?php
abstract class ClassA {
static $property;
public static function init() {
self::$property = new ClassB();
}
} ClassA::init();
?>
Please note that the class doesn't have to be abstract for this to work.
See also How to initialize static variables and https://stackoverflow.com/a/3313137/118153.
This is a few years old, but I just ran into a issue where I have a base class
class GeneralObject
{
protected static $_instance;
public static function getInstance()
{
$class = get_called_class();
if(!isset(self::$_instance))
{
self::$_instance = new $class;
}
return self::$_instance;
}
}
That has a Child Class
class Master extends GeneralObject
{
}
And another Child class
class Customer extends Master
{
}
But when I try to call
$master = Master::getInstance();
$customer = Customer::getInstance();
then $master will be Master as expected, but $customer will be Master because php uses the GeneralObject::$_instance for both Master and Customer
The only way I could achieve what I want was to change the GeneralObject::$_instance to be an array and adjust the getInstance() method.
class GeneralObject
{
protected static $_instance = array();
public static function getInstance()
{
$class = get_called_class();
if(!isset(self::$_instance[$class]))
{
self::$_instance[$class] = new $class;
}
return self::$_instance[$class];
}
}
I hope this helps someone else out there. Took me a few hours to debug what was going on.

PHP 5.3 Abstract singleton class and childrens?

i has singleton class with final static method "getInstance()":
<?php
abstract class Singleton
{
protected static $instances;
final public static function getInstance()
{
$class = get_called_class();
if(!isset(static::$instances[$class]))
static::$instances[$class] = new $class();
return static::$instances[$class];
}
}
And code like this:
<?php
class C1 extends Singleton { }
class C2 extends Singleton { }
C1::getInstance(); // Created C1 class
C2::getInstance(); // Still get C1 class, get_called_class() return C1 when i try get C2
What i'm do wrong?
The reason this isn't working is that you're not creating a $instance property for each of your subclasses. While using static:: and get_called_class() will access subclass members instead of superclass members, if the members don't exist in the subclass then they will fall back to the ones defined in the superclass. The result of this is that you'll end up getting the same member anyway.
Try defining your subclasses like this instead.
class C1 extends Singleton {
protected static $instances;
}
class C2 extends Singleton {
protected static $instances;
}
C1->getInstance();
C2->getInstance();
should be
C1::getInstance();
C2::getInstance();
The code
Update:
You don't need an array to hold the instances, instead, let the subclass the hold. Try the code below.
class Singleton
{
private function __construct(){}
protected static $instance;
final public static function getInstance()
{
$class = get_called_class();
if(!static::$instance)
static::$instance = new $class();
return static::$instance;
}
}
class C1 extends Singleton {
protected static $instance;
}
class C2 extends Singleton {
protected static $instance;
}
var_dump(C1::getInstance());
var_dump(C2::getInstance());
Try this abstract Singleton:
abstract class Singleton
{
private static $_instances = array();
public static function getInstance()
{
$class = get_called_class();
if (!isset(self::$_instances[$class])) {
self::$_instances[$class] = new $class();
}
return self::$_instances[$class];
}
}
I can't reproduce your problem:
var_dump(C1::getInstance());
var_dump(C2::getInstance());
gives:
object(C1)#1 (0) {
}
object(C2)#2 (0) {
}
As the var_dump output shows, the types are different (C1, then C2). Keep in mind that you need to invoke the getInstance() statically as it's a static function.
Next to that if you want to really implement the Singleton pattern in PHP, your abstract class is missing some important method definitions to make this more precise with PHP. See Patterns­PHP Manual.
Also in PHP you normally do not need a Singleton at all, inject dependencies instead which will make your code more fluent.
Hope this is helpful.
Working version of abstract singleton:
abstract class Singletone {
private static $_instance = NULL;
private function __construct(){}
public static function GetInstance() {
if( !static::$_instance ) {
static::$_instance = new static();
}
return static::$_instance;
}
}
The derived class must overwrite the $_instance
class DefaultRouter extends Singletone {
protected static $_instance = NULL;
}
There's no need to redefine the static $instance property in the child classes, just use the one defined in the superclass:
<?php
class Singleton
{
public static $Instance;
private function __construct() { }
public static function GetInstance() {
if(!Singleton::$Instance) {
Singleton::$Instance = new static();
}
return Singleton::$Instance;
}
}
class MyClass extends Singleton
{
public $field1;
public $field2;
public $field3;
public function __construct()
{
$this->field1 = "field1";
$this->field2 = "field2";
$this->field3 = "field3";
}
}
var_dump(Myclass::GetInstance());
?>
It outputs
object(MyClass)#1 (3) {
["field1"]=>
string(6) "field1"
["field2"]=>
string(6) "field2"
["field3"]=>
string(6) "field3"
}
https://eval.in/306503

How can I create a singleton in PHP?

I'm using PDT and Aptana on Eclipse Indigo with PHP 5.3 and I want to create a singleton in a class.
By singleton, I mean I want to just have one instance of that object, and for other objects or classes to get that single instance via a function that returns that object (so this would mean I'm trying to create an object within the class that defines that object, ie: creating objA within the class objA)
I understand you can't just go a head and do this:
public $object = new Object();
with in a class definition, you have to define it in the constructor.
How can I go ahead and do this? I'm coming from Java, so it could be I'm confusing some basic stuff. Any help is greatly appreciated. Here's the code:
<?php
class Fetcher{
private static $fetcher = new Fetcher(); //this is where I get the unexpected "new" error
static function getFetcherInstance(){
return $this->$fetcher;
}
}
?>
Solved! Thanks for all the help guys!
try this:
<?php
class myclass{
private static $_instance = null;
public static function getInstance() {
if (self::$_instance === null) {
self::$_instance = new myclass();
}
return self::$_instance;
}
}
?>
and call it with:
<?php
$obj = myclass::getInstace();
?>
You cannot assign a class property in PHP like that. It must be a scalar, or array value, or the property must be set in a method call.
protected static $fetcher;
static function getFetcherInstance(){
if (!self::$fetcher) {
self::$fetcher = new Fetcher();
}
return self::$fetcher;
}
Also, notice that I did not use $this->, as that only works for object instances. To work with static values you need to use self:: when working within the class scope.
You might want to just read common design patterns on the php site. There are pretty good examples with good documentation:
http://www.php.net/manual/en/language.oop5.patterns.php
Else, a singleton is simply a method that returns one single instance of itself:
class MySingletonClass {
private static $mySingleton;
public function getInstance(){
if(MySingletonClass::$mySingleton == NULL){
MySingletonClass::$mySingleton = new MySingletonClass();
}
return MySingletonClass::$mySingleton;
}
}
Building on #periklis answer you might want separate singletons for different application scopes. For example, lets say you want a singleton of a database connection - fine. But what if you have TWO databases you need to connect too?
<?php
class Singleton
{
private static $instances = array();
public static function getInstance($name = 'default')
{
if ( ! isset(static::$instances[$name]))
{
static::$instances[$name] = new static();
}
return static::$instances[$name];
}
}
Class DB extends Singleton {}
$db_one = DB::getInstance('mysql');
$db_two = DB::getInstance('pgsql');
Alse define __clone method
class Fetcher {
protected static $instance;
private function __construct() {
/* something */
}
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new Fetcher();
}
return self::$instance;
}
private function __clone() {
/* if we want real singleton :) */
trigger_error('Cannot clone', E_USER_ERROR);
}
}
Basically implementing a singleton pattern means writing a class with a private constructor and a static method to build itself. Also check PHP site for it: http://www.php.net/manual/en/language.oop5.php and http://it2.php.net/manual/en/book.spl.php
class A {
protected $check;
private function __construct($args) {
}
static public function getSingleton($args) {
static $instance=null;
if (is_null($instance)) {
$instance=new A();
}
return $instance;
}
public function whoami() {
printf("%s\n",spl_object_hash($this));
}
}
$c=A::getSingleton("testarg");
$d=A::getSingleton("testarg");
$c->whoami(); // same object hash
$d->whoami(); // same object hash
$b= new A("otherargs"); // run time error
<?php
class MyObject {
private static $singleInstance;
private function __construct() {
if(!isset(self::$singleInstance)) {
self::$singleInstance = new MyObject;
}
}
public static function getSingleInstance() {
return self::$singleInstance;
}
}
?>
class MyClass {
private static $instance;
public static function getInstance() {
if( !isset( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
}
Then call get instance using
MyClass::getInstance();

Categories