主要对比self关键字与static关键字的区别,self永远指向定义它的类,是静态值,static指向调用它的类,是动态值。特别是在单例模式下,在没有彻底理解self与static的情况下,很容易坠入逻辑陷阱。
class A{
protected static $instance;
protected static $instance_p;
public static function singleton(){
if (!static::$instance) {
$instance = new static();
static::$instance = $instance;
}
return static::$instance;
}
public static function singleton_p(){
if (!self::$instance_p) {
$instance = new self();//所有继承A的子类调用singleton_p实例化的都是A.
self::$instance_p = $instance;
}
return self::$instance_p;//instance class is A.
}
public static function who(){
echo 'Called A who, ', __CLASS__, ' ', self::class, ' ', static::class, "";
}
public static function callWho(){
self::who();
static::who();
}
}
class B extends A{
protected static $instance;
protected static $instance_p;
public static function who(){
echo 'Called B who, ', __CLASS__, ' ', self::class, ' ', static::class, "";
}
public static function callWho(){
parent::callWho();
self::who();
static::who();
}
}
class C extends A{
protected static $instance;
protected static $instance_p;
}
B::callWho();
//output, format messages, _CLASS_ self::class static::class
//Called A's who, A A B
//Called B's who, B B B
//Called B's who, B B B
//Called B's who, B B B
echo "";
$b = B::singleton();
echo get_class($b), "
";//B
$c = C::singleton();
echo get_class($c), "";//C
$b2 = B::singleton_p();
echo get_class($b2), "";//A
$c2 = C::singleton_p();
echo get_class($c2), "";//A
?>
另外我们要考虑到,B和C中的属性$instance是必须的,这样才能保证彼此互不干扰。
如果B和C都去掉$instance的话,那么它们将同时继承父类A的$instance属性,
这样一来,B和C将只能持有一个共同的$instance,这个$instance到底是谁的实例,
取决于哪个类最先被实例化。比如B最先调用了singleton方法,那么C再调用singleton方法时,
是无法重新创建实例的,它只能沿用B的那个实例。