【问题标题】:Singleton initialization configuration单例初始化配置
【发布时间】:2012-06-20 07:59:20
【问题描述】:

有一个公共库,有一个类在一个PHP进程中只能有一个实例,所以是Singleton。问题是这个类的初始化需要一些配置参数,我找不到在类构造函数中传递它们的好问题。

我发现的唯一问题是:

    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;
}

但我觉得这不是很好。还有其他想法吗?

谢谢!

【问题讨论】:

  • 单例模式不适用于只能有一个实例的类。它适用于可能有只有一个实例并且需要全局访问点的类。
  • 这就是单例很难的原因之一。如果您在应用程序中需要 one 并且需要使用参数对其进行实例化,那么您应该将 one 放置在您编写 new Foo($params) 的代码中,然后注入该实例任何需要它的地方......
  • 单身人士很少有合法用途,应该避免。 stackoverflow.com/a/9227695/477127
  • @SeniorDev 当然很重要。为了提出正确的解决方案,您需要了解您要解决的问题以及原因。否则,您只是假设这里需要一个 Singleton。所以问领域专家为什么(五次)必须只有一个实例以及当有两个实例时会产生什么后果。大多数情况下,简单地不实例化第二个实例而不是强制执行它就足够了。
  • 如果你在运行脚本的不同点需要不同的配置,那真的强烈建议你需要不止一个。

标签: php singleton


【解决方案1】:

有一个坏的例子,但工作问题:

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;
  }
}

【讨论】:

  • 这就是你认为的“参数化类”? ) 顺便说一句,如果有人决定扩展您的 PseoudoSingleton 类,您认为您的 __construct 方法会发生什么?
  • 这只是一些问题的例子。而且我已经写过它不好
  • 好的,你为什么不举例说明如何在你的情况下使用这个类(在一个完美的世界中,而不是这样)?不知何故,我开始认为在这里使用 Factory 会更合适......
  • class DB { protected function __construct($host = DB_HOST) { ...但这不是很好的例子,也不是我的真实案例。
【解决方案2】:
/* 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; 
}

【讨论】:

  • 不太好,但还有一个真正有效的问题。谢谢你,羊驼。
【解决方案3】:

单例实现示例:

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;
   }
}

注意构造函数是私有的,所以只能从类本身调用。 实例的引用只能通过 getInstance 调用获得,它在第一次调用时创建对象,任何后续调用都将返回对现有对象的引用。

【讨论】:

  • 不知何故,我想 OP 知道如何使用 Singleton。 )
  • @raina77ow 在阅读相关代码时,我不确定 100% ;)
【解决方案4】:

为什么要检查两次?

只需执行以下操作:

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;
}

这样,您知道您只需要检查一次,并且您知道只有在实例未初始化时才调用 init()。

【讨论】:

  • 没办法 :( ClassName::getInstance($params1); ClassName::getInstance($params2); // FAIL: $params2 被忽略,开发者很困惑
  • 恕我直言,您建议的方案违背了单例的目的,因为您暗示您想要有 2 个实例。此外,如果您采用该方案并将其用于您的代码,您将得到相同的结果!所以这里的问题是你的问题,而不是我的答案!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-26
  • 1970-01-01
相关资源
最近更新 更多