0

I am trying to implement the singleton pattern in php like described here in Example #2: http://www.php.net/singleton

When I run the example code

$singleton = Example::singleton(); // prints "Creating new instance."
echo $singleton->increment(); // 0
echo $singleton->increment(); // 1

$singleton = Example::singleton(); // reuses existing instance now
echo $singleton->increment(); // 2
echo $singleton->increment(); // 3

it allways ends with Fatal Error 'Clone is not allowed.' directly after 'Creating new instance.'

I would expect that there is no reason for php to call the __clone-method. In another real-life project of mine I want to have a singleton PlayerManager that holds Player-objects in an array (loaded only once in __construct) and has functions like GetPlayers() or GetPlayersByID($id).

In my script I write something like

$pm = PlayerManager::GetInstance();
$p1 = $pm->GetPlayerByID(0);
echo $p1->SomeNumber; //100

$p1->SomeNumber = 200;
$p2 = $pm->GetPlayerByID(0);
echo $p2->SomeNumber; //100 and not 200, as I would expect

Can someome give me some hints how to implement the PlayerManager using the Singleton pattern correct? I'm not sure if it is only a problem with the singleton or also a problem with returning object references...

1 Answers1

1

I'm not quiet sure why you're getting that error (post your singleton class if you want help with that). Though I always preferred this version to the one you're using, it's a bit simpler: http://www.talkphp.com/advanced-php-programming/1304-how-use-singleton-design-pattern.html

So with the above, your code would look like:

class Counter
{
    $CurrentValue = 0;

    // Store the single instance of Database 
    private static $m_pInstance; 

    private function __construct() { } 

    public static function getInstance() 
    { 
        if (!self::$m_pInstance) 
        { 
            self::$m_pInstance = new Counter(); 
        } 

        return self::$m_pInstance; 
    }

    public function increment ($by)
    {
        $this->CurrentValue += $by;
        return $this->CurrentValue;
    }
    public function getValue ()
    {
        return $this->CurrentValue;
    }
}

And to use:

$counter = Counter::getInstance();
echo $counter->increment(); // 0
echo $counter->increment(); // 1

$counter = null;

$counter = Counter::getInstance(); // reuses existing instance now
echo $counter->increment(); // 2
echo $counter->increment(); // 3

Tell me how that works out for you.

Jess
  • 8,628
  • 6
  • 49
  • 67
  • 1
    its also no longer a Singleton because it can be cloned and unserialized. The purpose of the Singleton pattern is to **make sure** there can be only one instance and provide a global access point to it. – Gordon Jan 30 '12 at 23:04
  • grossvogel Thanks for the code review, @Gordon A fair point, though to my understanding php never clones classes, and only does so when you directly tell it to. So unless you're trying to protect the code from yourself I see no issue with it, though I might have missed something? – Jess Jan 30 '12 at 23:07
  • well if that is the argument then why have a Singleton in the first place. After all, it's you who will call getInstance() in your code as well. With that argument you can simply do what you should do anyway: [Create Once Only](http://butunclebob.com/ArticleS.UncleBob.SingletonVsJustCreateOne) – Gordon Jan 30 '12 at 23:10
  • I've had many times where I wanted to share say a database class over multiple other classes. The singleton pattern is designed to share a single resource easily (say logs or a database connection) not a tie a coders hands. I'm not disagreeing with your point that isn't a true singleton pattern, I'm just pointing out that it would work fine for most (if not all) situations. – Jess Jan 30 '12 at 23:12
  • It's a creational pattern, so I have to disagree it's about sharing easily. Global Access is one only purpose of it. But if it was about global access only, you could simply use a static class. Or create a regular instance on top of your script and pull it in with the `global` keyword. It might sound pedantic, but if your version is good enough, its proof that you dont need a Singleton in the first place. I'd also argue [there is no UseCase for Singletons in PHP](http://stackoverflow.com/questions/4595964/who-needs-singletons/4596323#4596323) but that's a different story. – Gordon Jan 30 '12 at 23:29
  • I would argue the same thing, singletons are (by my definition) an easy way out of coding something well. Though that's why I like it I suppose, it's saved me days of re-factoring defunct code to add something. I use them because they give you the construct and others (like __get and __set) unlike static, and you don't need the global keyword in *every* function. They have their niche. – Jess Jan 30 '12 at 23:34
  • I wouldnt call shooting myself in the foot a niche, but hey, that's just me ;) – Gordon Jan 30 '12 at 23:45
  • Haha, psh, I won't be the one that does it, it's all the other devs that do that XD – Jess Jan 31 '12 at 00:18
  • Thx for the answers. I'm using PHP Version 5.2.4-pl2-gentoo, if it is important to know. I tried your code: $counter = Counter::getInstance(); echo $counter->increment(1).'
    '; // 1 echo $counter->increment(1).'
    '; // 2 echo $counter->increment(1).'
    '; // 3 $counter = null; $counter = Counter::getInstance(); // reuses existing instance now echo $counter->increment(1).'
    '; // 4 echo $counter->increment(1).'
    '; // 5 echo $counter->increment(1).'
    '; // 6 Result is: 1 2 3 1 2 3 It seems that i'm getting a completely new instance, no idea why.
    – Steven Grigoleit Feb 15 '12 at 08:15