共计 2100 个字符,预计需要花费 6 分钟才能阅读完成。
误解的一般解释
__call
方法在对象方法不存在的时候被调用
__callStatic
方法在调用对象静态方法不存在的时候被调用
例如
class Car{public function __call($method,$params=[]){echo "car call\n";}
}
(new Car())->color();
class Bus{public static function __callStatic($method,$params=[]){echo "Bus callStatic\n";}
}
Bus::isSale();
特殊情况
其实上面的解释在某些情况下是正确的。但是在一些特殊情形,如果按照这个解释来理解,就会觉得结果不可思议了。
以下面几个例子进行说明。
__call 的调用关注的是方法能不能被访问
class Car{public function __call($method,$params=[]){echo "car call\n";}
public function color(){echo "color red\n";}
protected function isRed(){echo "yes is Red\n";}
public function checkColor(){$this->color();
$this->isRed();}
}
$car = new Car();
$car->color();
$car->isRed();
$car->checkColor();
输出的结果是
color red
car call isRed
color red
yes is Red
从上面可以看出,其实是否调用__call
, 依赖的是当前调用方能否访问到要调用的函数,如果可以访问到,则直接调用函数,如果不能访问到,则调用魔术方法__call
。所以,调用与否关注的是可访问性。
__callStatic 关注的是方法能否被静态的方式访问
接下来看另外一个静态调用的例子
class Car{public static function __callStatic($method,$params=[]){echo "car callStatic\n";}
public function color(){echo "color red\n";}
protected function isRed(){echo "yes is Red\n";}
public function checkColor(){Car::color();
Car::isRed();}
}
Car::color();
Car::isRed();
(new Car())->checkColor();
输出内容是
color red
car callStatic isRed
color red
yes is Red
并且在外部以静态方式调用 Car::color
伴有 Notice
级别错误提示,但是内部调用是没有的。
所以,__callStatic
关注的是函数在调用位置能否被静态的方式访问到。如果能访问到,则直接执行该方法。如果不能则执行 __callStatic
方法
__call 与__callStatic 同时存在的情况
方法不可访问的时候,具体调用__call,__callStatic 方法,依据的并不是调用方式是否是静态调用,而是所在的上下文。如果上下文是在可访问调用对象的对象里,则调用__call
,在静态上下文中调用一个不可访问方法时,调用__callStatic
class Car{public static function __callStatic($method,$params=[]){echo "car callStatic $method\n";}
public function __call($method,$params=[]){echo "car call $method\n";}
public function checkColor(){Car::color();
Car::isRed();}
}
$car = new Car();
Car::color();
Car::isRed();
$car->color();
$car->isRed();
(new Car())->checkColor();
输出内容是
car callStatic color
car callStatic isRed
car call color
car call isRed
car call color
car call isRed
从结果看出,外部静态调用 color
,isRed
方法,上下文是静态方式,所以执行的是__callStatic
。
而在 checkColor
方法中,调用的上下文处于当前类对象 Car
当中,即使是以静态方式调用 color
,isRed
,最终执行的是__call
方法。
总结
1)__call
方法关注方法能否被访问到,而不仅仅是关注是否存在
2)__callStatic
方法关注的是方法能否被静态的访问到,而不是关注方法是否存在,是否是静态方法。
3)具体执行__call
,__callStatic
,是根据调用的上下文。如果处于静态上下文内,则调用__callStatic
。如果处于对象的上线文内,则调用__call
文章首发于公众号【写 PHP 的老王】,转载注明出处