Page 1 of 1

Semi Singleton

Posted: Sat Aug 19, 2006 11:10 am
by Benjamin
How can I make a class that populates a variable with the first instance of itself? I want to be able to call the class so that I can retrieve the first instantiated instance..

Code: Select all

class whatsupyo {
    private static $instance = false;

    function __construct() {
        if ($instance === false) {
            $instance = ?
        }
    }

    function get_instance() {
        return $instance;
    }

Posted: Sat Aug 19, 2006 11:18 am
by feyd
There's something fishy with doing this but..

Code: Select all

class foo
{
  private static $instance = null;

  public function __construct()
  {
    if (self::$instance === null)
    {
      self::$instance = $this;
    }
    else
    {
      throw new SingletonException();
    }
  }

  public static function GetInstance()
  {
    if (self::$instance === null)
    {
      $class = __CLASS__;
      new $class();
    }
    return self::$instance;
  }
}
edit: possible logic fix.

Posted: Sat Aug 19, 2006 11:22 am
by Jenk
Why not lazy load the in the getInstance method instead?

That way, no matter what calls it first, aslong as they call the getInstance method you'll always have a singleton?

in other words, I don't see what this will achieve.

Posted: Sat Aug 19, 2006 11:40 am
by Benjamin
I don't want it to be a singleton, but I want to be able to retrieve the first instance without using a registry or global variable. Hence I figured this would work. Works great using $this.

Posted: Sat Aug 19, 2006 11:41 am
by feyd
astions wrote:I want to be able to retrieve the first instance without using a registry or global variable.
That's the general definition of a singleton.

Posted: Sat Aug 19, 2006 11:45 am
by Benjamin
I also need to be able to instantiate new instances of it, although, come to think of it, maybe it would be better to make copies of it.

Posted: Sat Aug 19, 2006 11:58 am
by feyd
I don't like the concept, but this is what you are looking for.

Code: Select all

class foo
{
  private static $instance = null;
  protected $bar;

  public function __construct()
  {
    if (self::$instance === null)
    {
      self::$instance = $this;
    }
    $this->bar = mt_rand(1,100);
  }

  public static function GetFirstInstance()
  {
    if (self::$instance === null)
    {
      $class = new ReflectionClass(__CLASS__);
      $class->newInstance();
    }
    return self::$instance;
  }
}

$foo1 = new foo();
$foo2 = new foo();
$foo3 = foo::GetFirstInstance();
var_dump($foo1 === $foo2, $foo2 === $foo3, $foo1 === $foo3, $foo1, $foo2, $foo3);

Posted: Sat Aug 19, 2006 12:05 pm
by Benjamin
feyd, I was in the process of posting this while you posted your example. I'll use your example, but can you tell me why this doesn't work?

Code: Select all

class test {
    private static $instance = false;

    function __construct() {
        if (self::$instance === false) {
            self::$instance = $this;
        }
    }

    public static function getInstance(){
        return self::$instance;
    }
}

$activate = new test();

// and I try to get the instance with..
$test = test::getInstance();

Posted: Sat Aug 19, 2006 12:14 pm
by feyd
It appears to work for me.

Posted: Sat Aug 19, 2006 1:30 pm
by Chris Corbyn
I don't understand the reason for putting the singleton logic in the constructor. Eeven if you had that same logic in the factory method for it you'd essentially have the same thing.

~astions, have you looked at using a registry? That would give you far more flexibility and allow to store mutliple instances if you wanted to, whilst still be able to refer to an instance over and over like a singleton without needing to pass it from object to object at each step.

Posted: Sat Aug 19, 2006 2:05 pm
by Benjamin
It's in the constructor to ensure that the first instance is captured.

As far as a registry is concerned, I've considered that, but with this method, which might just very well be a new pattern, I avoid using a registry, I can get an instance of the class from any other class without using globals, and I can still create a new instance if I need to.

Posted: Sat Aug 19, 2006 2:40 pm
by Chris Corbyn
astions wrote:I can get an instance of the class from any other class without using globals, and I can still create a new instance if I need to.
I'd change your singleton factory to this:

Code: Select all

public static function getInstance(){
        if (self::$instance === null) self::$instance = new test();
        return self::$instance;
    }
Otherwise, how can you be sure you'll return a singleton? For your code to work you need to already have a live instance before the singleton will be returned ;)

Posted: Sat Aug 19, 2006 2:42 pm
by Benjamin
Yeah I was going to do that, Thanks for the good example though, now I can just plug it in :)