1

There is a public library, and there is a class that can have only one instance in one PHP process, so it's Singleton. The problem is that initialization of this class require some configuration arguments and I can't find good issue to pass them in class constructor.

The only issue I found is:

    public static function init($params) {
    if(self::$instance) {
        throw new Exception(__CLASS__ . ' already initialized');
    }
    $class = __CLASS__;
    self::$instance = new $class($params);
}

public static function getInstance() {
    if(!self::$instance) {
        throw new Exception(__CLASS__ . ' is not initialized');
    }
    return self::$instance;
}

But I don't think that it's so really good.Is there any other ideas?

Thanks!

PeeHaa
  • 71,436
  • 58
  • 190
  • 262
barbushin
  • 5,165
  • 5
  • 37
  • 43
  • 4
    Singleton is not an applicable pattern for classes that **can have** only one instance. It's for classes that **may have** only one instance **and** that need a a global access point to it. – Gordon Jun 18 '12 at 10:55
  • 3
    And that's one reason why singletons are difficult. If you need *one* inside your app and you need to instantiate it with parameters, then you should have *one* place in your code where you write `new Foo($params)` and then inject that instance everywhere it's needed... – deceze Jun 18 '12 at 10:56
  • Singletons have very few legitimate uses and should be avoided. http://stackoverflow.com/a/9227695/477127 – GordonM Jun 18 '12 at 10:58
  • @deceze But in this way I can't guarantee that there will be only one instance of this class. – barbushin Jun 18 '12 at 10:59
  • Yes, so? :) What's the specific reason you want yo lock down the usage of the class so hard? – deceze Jun 18 '12 at 11:01
  • @Gordon Yes, I know :) But is there any other issue for described case? As I know using different kind of "Dependency Injection" does not guarantee unique instance of class objects. – barbushin Jun 18 '12 at 11:02
  • @SeniorDev why do you have to guarantee it? Will kittens die when you dont do it? – Gordon Jun 18 '12 at 11:02
  • @deceze It's just very important in described case. For example: there is one STDOUT handler, and it MUST be configured on initialization, and there MUST be only one instance. – barbushin Jun 18 '12 at 11:05
  • @Gordon It's just very important in described case. For example: there is one STDOUT handler, and it MUST be configured on initialization, and there MUST be only one instance. – barbushin Jun 18 '12 at 11:06
  • @SeniorDev but why? what is the reason? – Gordon Jun 18 '12 at 11:08
  • @Gordon It does not matter :) There is a unique case, and I need some issue. I don't ask about "how to except unique instance dependency?", I'm asking about "how to configure it?". – barbushin Jun 18 '12 at 11:13
  • 2
    @SeniorDev of course it matters. In order to come up with the right solution, you need to understand what you are trying to solve and why. Otherwise, you are just assuming to need a Singleton here. So ask the Domain Expert why (five times) there MUST be only one instance and what the consequences are when there is two instances. Most of the time, it is sufficient to simply not instantiate a second instance instead of enforcing it. – Gordon Jun 18 '12 at 11:34
  • 1
    If you need different configurations for it at different points in the running script, that really strongly suggests that you need more than one of it. – GordonM Jun 18 '12 at 11:35
  • Hopefully, you found what you were searching for! :-) – Fabrizio Bertoglio May 11 '19 at 21:45

4 Answers4

0

There is example of bad, but working issue:

if(!defined('PSEOUDSINGLETON_PARAM')) {
      define('PSEOUDSINGLETON_PARAM', 'default value');
}

class PseoudoSingleton {

  protected function __construct($param1 = PSEOUDSINGLETON_PARAM) { 
        // ... 
  }

  public static function getInstance() {
    if(!self::$instance) {
        $class = __CLASS__;
        self::$instance = new $class();
    }
    return self::$instance;
  }
}
barbushin
  • 5,165
  • 5
  • 37
  • 43
  • That's what you consider 'a parameterized class'? ) Btw, what do you think will happen to your __construct method if someone decides to extend your PseoudoSingleton class? – raina77ow Jun 18 '12 at 11:36
  • It's just example of some issue. And I already wrote that it's **bad**. – barbushin Jun 18 '12 at 11:41
  • Ok, why don't you give examples of how this class will be *used* in your case (in a perfect world, and not so)? Somehow I start to think that using Factory will be much more suitable here... – raina77ow Jun 18 '12 at 11:43
  • class DB { protected function __construct($host = DB_HOST) { ... but it's not very good example, and it's not about my real case. – barbushin Jun 18 '12 at 11:45
0
/* on library/utility level */
class nonSingletonService { public function __construct($options){} }

/* on application logic level, so, knows all context */
function getSingleton(){ 
   static $inst; 
   if (!$inst) $inst=new nonSingletonService(calculateParameters()); 
   return $inst; 
}
alpaca
  • 76
  • 1
  • 4
-1

Sample Singleton implementation:

class MySingleton
{
   private static $_INSTANCE = null;

   private function __construct()
   {
      // put initialization code here
   }

   public static function getInstance()
   {
       if(self::$_INSTANCE === null) self::$_INSTANCE = new MySingleton();
       return self::$_INSTANCE;
   }
}

Note that constructor is private, so it can only be called from the class itself. References to the instance can be only obtained by getInstance call, which creates the object on first call, any subsequent calls will return references to an existing object.

poncha
  • 7,726
  • 2
  • 34
  • 38
-1

Why are you checking it twice?

Just do the following:

private static function init($params) {       
    $class = __CLASS__;
    self::$instance = new $class($params);
}

public static function getInstance($params) {
    if(!self::$instance) {
        self::init($params);
    }
    return self::$instance;
}

That way, you know that you only need to check once and you know you only call init() if the instance is not initialized.

Tomer
  • 17,787
  • 15
  • 78
  • 137
  • No way :( ClassName::getInstance($params1); ClassName::getInstance($params2); // FAIL: $params2 is ignored, developer is confused – barbushin Jun 18 '12 at 11:34
  • With all due respect, the scenario you are suggesting defies the purpose of a singleton since you imply that you want to have 2 instances. Also, if you take that scenario and use it on your code you'll get the same! So the problem here is your question, not my answer! – Tomer Jun 18 '12 at 11:40