单例模式最佳实践
项目有个类需要使用单例模式,这我熟悉啊,眨眼之间就写了如下代码
class A
{
protected static $instance = null;
// 防止外部实例化
protected function __contruct(){}
// 防止克隆
protected function __clone(){}
public static function getInstance()
{
if (is_null(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
//todo
}
写完了,可以回家了,不过凭我多年写代码第六感的直觉,我隐约觉得好像哪里不对,瞟了一眼老司机的代码,如下
class A
{
protected static $instance = null;
// 防止外部实例化
protected function __contruct(){}
// 防止克隆
protected function __clone(){}
public static function getInstance()
{
if (is_null(static::$instance)) {
static::$instance = new static();
}
return static::$instance;
}
public function say()
{
echo 'I am A'.PHP_EOL;
}
}
看似一样,实则暗藏玄机,关键就在new static()
,你可能会说这个我知道,后期静态绑定,如果你这么认为,那么我只能说,恭喜你,答对了。如果你不知道这是啥,没关系,请看这里。
可是why要这么写呢,我脑海中出现了柯南后脑勺的那道闪电,继承。看下面代码
class A
{
protected static $instance = null;
// 防止外部实例化
protected function __contruct(){}
// 防止克隆
protected function __clone(){}
public static function getInstance()
{
if (is_null(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
public function say()
{
echo 'I am A'.PHP_EOL;
}
}
class B extends A
{
public function say()
{
echo 'I am B'.PHP_EOL;
}
public function test()
{
echo 'B test'.PHP_EOL;
}
}
$b = B::getInstance(); //$b是类A的实例
$b->test();
运行结果
PHP Fatal error: Uncaught Error: Call to undefined method A::test()
$b是类A的实例,但是我们需要类B的实例,使用new static()
的话,B::getInstance()
得到类B的实例,这对应后期静态绑定的非转发调用(non-forwarding call)。
在tp和laravel框架中,Container类是这样实现的单例,这种写法我觉得从语义上更清晰一些,但是功能上是一样的。
**
* Set the globally available instance of the container.
*
* @return static
*/
public static function getInstance()
{
if (is_null(static::$instance)) {
static::$instance = new static;
}
return static::$instance;
}