誤解的一般解釋
__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的老王】,轉載註明出處
本作品採用《CC 協議》,轉載必須註明作者和本文連結