__call, __callStatic и область вызова в PHP

Недавно я прочитал о вызове оператора сферы видимости и области видимости (: 🙂 в PHP. Существует два варианта: вызов экземпляра и статический вызов. Рассмотрим следующий список:

<?php class A { public function __call($method, $parameters) { echo "I'm the __call() magic method".PHP_EOL; } public static function __callStatic($method, $parameters) { echo "I'm the __callStatic() magic method".PHP_EOL; } } class B extends A { public function bar() { A::foo(); } } class C { public function bar() { A::foo(); } } A::foo(); (new A)->foo(); B::bar(); (new B)->bar(); C::bar(); (new C)->bar(); 

Результатом выполнения (PHP 5.4.9-4ubuntu2.2) является:

 I'm the __callStatic() magic method I'm the __call() magic method I'm the __callStatic() magic method I'm the __call() magic method I'm the __callStatic() magic method I'm the __callStatic() magic method 

Я не понимаю, почему для (new C)->bar(); выполнить __callStatic() A ? Вызов экземпляра должен выполняться в контексте метода bar (), не так ли? Является ли это особенностью PHP?

Addition1:

Более того, если я не использую магические методы и явно вызываю, все работает так, как ожидалось:

 <?php class A { public function foo() { echo "I'm the foo() method of A class".PHP_EOL; echo 'Current class of $this is '.get_class($this).PHP_EOL; echo 'Called class is '.get_called_class().PHP_EOL; } } class B { public function bar() { A::foo(); } } (new B)->bar(); 

Результат для этого:

 I'm the foo() method of A class Current class of $this is B Called class is B 

В методе bar() в C вас есть A::foo(); :

 public function bar() { A::foo(); } 

Поскольку этот метод не создает экземпляр A , а C не расширяет A , оператор :: рассматривается как статический оператор, пытающийся вызвать статический метод A::foo() . Поскольку foo() не определен на A , он возвращается к методу __callStatic() .

Если вы хотите, чтобы он вызывал нестатический метод без расширения A , вам нужно создать экземпляр A :

 class C { public function bar() { $aInstance = new A(); $aInstance->foo(); } } 

Это связано с тем, что в этом случае у нас нет экземпляра класса A Заметить, что

  class B extends A 

Таким образом, new B дает нам доступ к нестатической версии A->foo .

Класс C не расширяет A поэтому доступны только статические методы A