I have an abstract class and a child that extends the abstract class. The child is supposed to be a sigleton. Here is simplified example of the abstract class:
abstract class AbstractClass{
protected static $instance = NULL;
abstract protected function meInit();
private function __construct(){
$this->meInit();
$this->init();
}
private function __clone(){}
static function getInstance(){
if (is_null(self::$instance)){
self::$instance=new self;
}
return self::$instance;
}
function init(){
'code here;
}
}
Here is simplified child class:
class ChildClass_A extends AbstractClass{
protected function meInit(){
'some code;
}
}
When I try to get an instance of the child $child = ChildClass_A::getInstance(); I get this error:
Fatal error: Cannot instantiate abstract class AbstractClass in
C:\wamp\www\Classes\AbstractClass.php on line 7
I suspect the culprit is in self::$instance=new self;. How should I redo it to achieve what I need?
You're almost there; you just can't use new self() like this because it's trying to do a new A(). Instead, use get_called_class() so that a new B is created instead.
// ONLY SUPPORTS ONE SUBCLASS
// KEEP READING BELOW FOR COMPLETE SOLUTION
abstract class A {
static protected $instance = null;
abstract protected function __construct();
static public function getInstance() {
if (is_null(self::$instance)) {
$class = get_called_class();
self::$instance = new $class();
}
return self::$instance;
}
}
class B extends A {
protected function __construct() {
echo "constructing B\n";
}
}
var_dump(B::getInstance()); // constructing B, object(B)#1 (0) {}
var_dump(B::getInstance()); // object(B)#1 (0) {}
OK, but what happens now when we try to make another subclass?
class C extends A {
protected function __construct() {
echo "constructing C\n";
}
}
var_dump(C::getInstance()); // object(B)#1 (0) {}
var_dump(C::getInstance()); // object(B)#1 (0) {}
Well that sucks! I wanted a C instance, not the B one! This is because the abstract class A is only saving one instance. We have to make it support one of each subclass.
Well that's easy!
// SOLUTION:
// WORKS FOR MULTIPLE SUBCLASSES
abstract class A {
static protected $instances = array();
abstract protected function __construct();
static public function getInstance() {
$class = get_called_class();
if (! array_key_exists($class, self::$instances)) {
self::$instances[$class] = new $class();
}
return self::$instances[$class];
}
}
Class B and C can stay the same ...
class B extends A {
protected function __construct() {
echo "constructing B\n";
}
}
class C extends A {
protected function __construct() {
echo "constructing C\n";
}
}
Now let's check out how they behave
var_dump(B::getInstance()); // constructing B, object(B)#1 (0) {}
var_dump(B::getInstance()); // object(B)#1 (0) {}
var_dump(C::getInstance()); // constructing C, object(C)#2 (0) {}
var_dump(C::getInstance()); // object(C)#2 (0) {}
Oh good! Just what we always wanted!
Related
I am trying to execute initialize() method for each class that extends from a baseClass, by using late static bindings:
class BaseClass
{
protected static $initialized = false;
public static function find()
{
static::initialize();
//TODO search entries and return as instances...
}
protected static function initialize()
{
if (static::$initialized)
return;
echo 'Initializing ', static::class, '<br/>';
//do important stuff
static::$initialized = true;
}
}
class Child1 extends BaseClass {}
class Child2 extends BaseClass {}
$initialized property is being shared across the extending classes.
Child1::find(); //Outputs 'Initializing Child1', as expected
Child2::find(); //Doesn't execute 'initialize()' because
//$initialized property was set to true by Child1
//Expected: 'Initializing Child2'
Is there a simple way to achieve it?
You can change $initialized to an array (as suggested in comment) using class names as keys:
class BaseClass
{
protected static $initialized = [];
public static function find()
{
return static::initialize();
}
protected static function initialize()
{
$class_name = static::class;
if (!empty(static::$initialized[$class_name])) {
return static::$initialized[$class_name];
}
echo 'Initializing ', $class_name, '<br/>';
//do important stuff
static::$initialized[$class_name] = new static();
// do another important stuff and return instance
return static::$initialized[$class_name];
}
}
class Child1 extends BaseClass {}
class Child2 extends BaseClass {}
How can I return an instance of the class being called, when the method is in a parent class.
Eg. In the example below, how can I return an instance of B if I call B::foo();?
abstract class A
{
public static function foo()
{
$instance = new A(); // I want this to return a new instance of child class.
... Do things with instance ...
return $instance;
}
}
class B extends A
{
}
class C extends A
{
}
B::foo(); // Return an instance of B, not of the parent class.
C::foo(); // Return an instance of C, not of the parent class.
I know I can do it something like this, but is there a neater way:
abstract class A
{
abstract static function getInstance();
public static function foo()
{
$instance = $this->getInstance(); // I want this to return a new instance of child class.
... Do things with instance ...
return $instance;
}
}
class B extends A
{
public static function getInstance() {
return new B();
}
}
class C extends A
{
public static function getInstance() {
return new C();
}
}
$instance = new static;
You're looking for Late Static Binding.
http://www.php.net/manual/en/function.get-called-class.php
<?php
class foo {
static public function test() {
var_dump(get_called_class());
}
}
class bar extends foo {
}
foo::test();
bar::test();
?>
Result
string(3) "foo"
string(3) "bar"
So your function is going to be:
public static function foo()
{
$className = get_called_class();
$instance = new $className();
return $instance;
}
All you need is :
abstract class A {
public static function foo() {
$instance = new static();
return $instance ;
}
}
Or
abstract class A {
public static function foo() {
$name = get_called_class() ;
$instance = new $name;
return $instance ;
}
}
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 PatternsPHP 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
From php manual:
[...] Static method calls are resolved at compile time.
When using an explicit class name the method is already identified completely and no
inheritance rules apply. If the call is done by self then self is translated to
the current class, that is the class the code belongs to.
Here also no inheritance rules apply [...]
..so im looking for a way to emulate the standard oop inheritance with static singleton.
Code explain better:
// Normal inheritance: my goal.
class Foo{
public function test(){
echo "Foo->test()\n";
}
}
class Bar extends Foo{
public function other_test()
{
echo "Bar->other_test()\n";
}
}
$obj = new Bar();
echo get_class($obj) . "\n";
$obj->test();
$obj->other_test();
/*
Output:
Bar
Foo->test()
Bar->other_test()
*/
// How i would love to do:
class Foo2{
public static function test2()
{
echo "Foo2::test2()\n";
}
// Singleton?
public static $_instance;
public static function get_instance()
{
if(is_null(self::$_instance))
{
self::$_instance = new self();
}
return self::$_instance;
}
}
class Bar2 extends Foo2{
public static function other_test2()
{
echo "Bar2::other_test2()\n";
}
}
$obj2 = Bar2::get_instance();
echo get_class($obj2) . "\n";
$obj2::test2();
$obj2::other_test2();
/*
Output:
Foo2
Foo2::test2()
Fatal error: Call to undefined method Foo2::other_test2()
*/
echo "\n-------\n";
// How im doing actually:
interface Foo3{
public static function get_instance();
}
class Bar3 implements Foo3{
// Singleton?
public static $_instance;
public static function get_instance()
{
if(is_null(self::$_instance))
{
self::$_instance = new self();
}
return self::$_instance;
}
public static function test3()
{
echo "Bar3::test3()\n";
}
public static function other_test3()
{
echo "Bar3::other_test3()\n";
}
}
$obj3 = Bar3::get_instance();
echo get_class($obj3) . "\n";
$obj3::test3();
$obj3::other_test3();
/*
Output:
Bar3
Foo3::test3()
Bar3::other_test3()
*/
The last 'way' force me to avoid the get_instance and static variables to be placed in the parent class, so I do not consider it as a best solution.. if for some reason my get_instance() function will change in the future, i dont want to edit all classes (inheritance! inheritance! we all want inheritance!)
So, is there a way or a best practices to solve this problem?
p.s: php5.3.2
The Singleton pattern in PHP is something like this:
class Singleton {
private static $instance = null;
// Constructor is private, so class cannot be instantiazed from outside
private function __construct() {
}
public static function getInstance() {
if (static::$instance === null) {
static::$instance = new Singleton();
}
return static::$instance;
}
public static function test() {
echo 'Singleton::test()';
}
public function __sleep() {
throw new Exception('Serialization is not alowed.');
}
public function __wakeup() {
throw new Exception('Serialization is not alowed.');
}
public function __clone() {
throw new Exception('Cloning is not alowed.');
}
}
For you is important that keyword static, then this:
class B extends Singleton {
public static function test2() {
echo 'B::test2()';
}
}
$b = B::getInstance();
B::test();
B::test2();
// Singleton::test()
// B::test()
Is this you looking for?
I have a simple question. I use a singleton which implements an abstract class. Is it possible to put the getInstance() Method and the variable $_instance in the abstract class instead of the concrete one I want to create?
Here's my code:
<?php
class Command_Log extends Command_Abstract {
private static $_instance=null;
public static function getInstance() {
if (self::$_instance==null)
self::$_instance=new self();
return self::$_instance;
}
protected function realExecute() {
}
protected function realSimulate($fileHandle) {
}
}
and
<?php
abstract class Command_Abstract implements Command_Interface {
protected $_data=array();
//private static $_instance=null;
protected $_isExecuted=false;
protected $_execute=false;
public function enableExecute() {
$this->_execute=true;
return $this;
}
protected function __construct() {
}
protected function __clone() {}
public function addData($data) {
array_push($this->_data,$data);
return $this;
}
abstract protected function realExecute();
abstract protected function realSimulate($fileHandle);
public function execute() {
if(!$this->_isExecuted && $this->_execute) {
$this->_isExecuted = true;
$this->realExecute();
}
}
public function simulate() {
$exitSystem = false;
if(!$this->_isExecuted && $this->_execute) {
$this->_isExecuted = true;
$exitSystem = $this->realSimulate($fh);
}
}
return $exitSystem;
}
}
I have many implementations of the the commands, so I don't want redundant code everywhere in my implementations. Is it possible to put these two things in the abstract class, if yes please tell me how.
If not please explain it to me why it isnt possbile. Or if I need to change something to do it, anyhow.
regards
YES WE CAN!
I have a class called Singleton that is abstract... and many classes that extends that Singleton class... this is the code:
abstract class Singleton {
private static $instances = array();
final private function __construct($_params) {
$class = get_called_class();
if (array_key_exists($class, self::$instances))
throw new Exception('An instance of '. $class .' already exists !');
//static::initialize(); //In PHP 5.3
$this->initialize($_params);
}
final private function __clone() { }
abstract protected function initialize();
public static function getInstance($_params=array()) {
$class = get_called_class();
if (array_key_exists($class, self::$instances) === false){
self::$instances[$class] = new $class($_params);
}
return self::$instances[$class];
}
}
and (for example) the class DBConnection that extends from Singleton
class DBConnection extends Singleton{
private $connexion_pdo=null;
protected function initialize(){
//connect to the DB
$this->connexion_pdo = blablalba;
}
}
although there are some problems in php 5.2.. specially with the function get_called_class() and the static::initialize()
You could also check the php site for patterns... there are lots of contributions for the singleton
Good Luck