2

I'd like to start by showing a test case:

class A {
    public static $instance=null;
    public function __construct(){
        self::$instance=$this;
    }
    public function className(){
        return get_class(self::$instance);
    }
}

class B extends A {
    public function className(){
        return get_class(self::$instance);
    }
}

// test code
$b=new B();
echo $b->className; // B
$a=new A();
echo $a->className; // A
echo $b->className; // A <- error: not B any more!

Notes

  • I'm using a factory+singleton patterns above. Well, somewhat.
  • I don't need any specs on "implementing patterns correctly". I need problem solving, not KISS violations ;).
  • Critics might say A should be an interface. Ideally, that's what it should have been, but it's just a simple class, sorry.

The issues lies in the fact that self::$instance is the same for all instances. How do I separate self::$instance for each class?

Edit: I've had this idea:

$GLOBALS['store']=array();
class A {
    public static $instance=null;
    public function __construct(){
        $GLOBALS['store'][__CLASS__]=$this;
    }
}
Christian
  • 27,509
  • 17
  • 111
  • 155
  • That's what static means. They are ALL using the same variable. So any change will change the variable. – DampeS8N Dec 17 '10 at 15:56
  • I'm not sure if `__CLASS__` is determined at run-time ... IMO it will always be 'A'. – giraff Dec 17 '10 at 16:01
  • 1
    Ah, I see what you are trying to do. Once you added extra info to the question that made that clear, it stopped being half-witted itself. – DampeS8N Dec 17 '10 at 16:05
  • @giraff: `__CLASS__` is determined at compile time... If you want to use late static binding (5.3+), use `static::$foo` instead of `self::$foo`... – ircmaxell Dec 17 '10 at 16:05

3 Answers3

3

You could store an instance per class name:

class A { 
    public static function getInstance(){
        // Maybe use this function to implement the singleton pattern ...
        return self::$instance[get_called_class()];
    }

    public function className(){
        return get_class(self::getInstance());
    }   
}
giraff
  • 4,601
  • 2
  • 23
  • 35
1

You can not do this the clean way. That is one of the mayor drawbacks on stati propertys: you cannot overrride them.

But you wantet an sollution so.....here is the worarround: use __calllStatic

  <?php 
 class A {
    public static function __callstatic($name,$args)
    {
        if($name="getClass"){
                return 'A';
        }
    }
 }

 class  B extends  A{
 public static function __callstatic($name,$args)
    {
        if($name="getClass"){
                return 'B';
        }
    }
 }


echo  A::getClass();
echo  B::getClass();
?>

the output of this is "AB";

Oliver A.
  • 2,870
  • 2
  • 19
  • 21
1

You can add a public static $instance=null; declaration in class B.

class A {
    public static $instance=null;
    public function __construct(){
        self::$instance=$this;
    }
    public function className(){
        return get_class(self::$instance);
    }
}

class B extends A {
    public static $instance=null;
    public function className(){
        return get_class(self::$instance);
    }
}

// test code
$b=new B();
echo $b->className(); // B
$a=new A();
echo $a->className(); // A
echo $b->className(); // Now returns B, as desired.
Aether
  • 364
  • 2
  • 5
  • I was aware of this (should have described it in the post). The issue with this is that class B would need to have "unnecessary code" to accommodate class A. Although usable, it's a bit inconvenient since `::$instance` was supposed to be "internal" anyway. +1 for the idea though; clearly shows OOP behaviour. – Christian Dec 20 '10 at 16:38