使用PHP 5.4构建Singleton特征

时间:2011-08-18 09:10:20

标签: php traits

我们最近讨论过是否有可能构建trait Singleton PHP Traits,我们在其中使用了可能的实施方案,但遇到了构建问题的问题。

这是一项学术活动。我知道Singletons have very little - if not to say no - use in PHPone should 'just create one',但仅仅是为了探索特征的可能性:

<?php
trait Singleton
{
    protected static $instance;
    final public static function getInstance()
    {
        return isset(static::$instance)
            ? static::$instance
            : static::$instance = new static;
    }
    final private function __construct() {
        static::init();
    }
    protected function init() {}
    final private function __wakeup() {}
    final private function __clone() {}    
}

class A  {
    use Singleton;
    public function __construct() {
        echo "Doesn't work out!";
    }
}

$a = new A(); // Works fine

重现:http://codepad.viper-7.com/NmP0nZ

问题是:可以在PHP中创建Singleton Trait吗?

5 个答案:

答案 0 :(得分:29)

我们找到了快速解决方案(谢谢聊天!):

如果一个特质和一个类都定义了相同的方法,那么使用一个类

所以Singleton特征只有在使用它的类没有定义__construct()

时才有效

特点:

<?php
trait Singleton
{
    protected static $instance;
    final public static function getInstance()
    {
        return isset(static::$instance)
            ? static::$instance
            : static::$instance = new static;
    }
    final private function __construct() {
        $this->init();
    }
    protected function init() {}
    final private function __wakeup() {}
    final private function __clone() {}    
}

消费类的示例:

<?php    
class A  {
    use Singleton;

    protected function init() {
        $this->foo = 1;
        echo "Hi!\n";
    }
}

var_dump(A::getInstance());

new A();

var_dump现在产生预期的输出:

Hi!
object(A)#1 (1) {
  ["foo"]=>
  int(1)
}

并且新的失败:

Fatal error: Call to private A::__construct() from invalid context in ...

Demo

答案 1 :(得分:2)

我刚刚创建了一个,当时我厌倦了尝试学习特质。它使用反射和__CLASS__常数

特点:

trait Singleton
{
private static $instance;

public static function getInstance()
{
    if (!isset(self::$instance)) {
        $reflection     = new \ReflectionClass(__CLASS__);
        self::$instance = $reflection->newInstanceArgs(func_get_args());
    }

    return self::$instance;
}
final private function __clone(){}
final private function __wakeup(){}
}

这样你就可以继续使用__construct()方法,而不需要使用任意函数作为构造函数。

答案 2 :(得分:1)

问题是getInstance返回的类型将是不明确的,因为它取决于消费者。这给出了弱类型的方法签名。 例如,它使得无法在getInstance方法doc bloc中提供符合使用者类型的@return。

答案 3 :(得分:1)

这是你所需要的所有人。 如果你希望你可以使用私有静态成员,但没有真正需要...... 尽管您可能认为静态将是全局的或其他东西,但经过测试仍然有效:)

trait Singleton
{
    /**
     * Singleton pattern implementation
     * @return mixed
     */
    public static function Instance()
    {
        static $instance = null;
        if (is_null($instance)) {
            $instance = new self();
        }
        return $instance;
    }
}

用法:

class MyClass
{
 use Singleton;
}

答案 4 :(得分:0)

派对有点晚了,但我想展示如何(至少在Eclipse Oxygen PDT中)你可以做DocBlock,其中自动完成将适用于此

trait SingletonTrait{

    /**
     *
     * @var self
     */
    private static $Instance;

    final private function __construct()
    { 
    }

    final private function __clone()
    {
    }

    final private function __wakeup()
    {
    }

    /**
     * 
     * Arguments passed to getInstance are passed to init(),
     * this only happens on instantiation
     * 
     * @return self
     */
    final public static function getInstance(){
        if(!self::$Instance){
            self::$Instance = new self;           
            self::$Instance->init();
        }       
        return self::$Instance;      
    }

    protected function init()
    {       
    }

}

正如您所看到的,$instancegetInstance都定义为self。 Eclipse很聪明,可以解决这个问题,所以当你在一个类中使用它时,所有的自动完成工作都正常。

测试

enter image description here