我们最近讨论过是否有可能构建trait Singleton
PHP Traits,我们在其中使用了可能的实施方案,但遇到了构建问题的问题。
这是一项学术活动。我知道Singletons have very little - if not to say no - use in PHP
和one 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吗?
答案 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();
Hi!
object(A)#1 (1) {
["foo"]=>
int(1)
}
Fatal error: Call to private A::__construct() from invalid context in ...
答案 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()
{
}
}
正如您所看到的,$instance
和getInstance
都定义为self
。 Eclipse很聪明,可以解决这个问题,所以当你在一个类中使用它时,所有的自动完成工作都正常。
测试