Допустим у вас есть класс, описывающий методы и свойства какого-либо объекта (что, в принципе, логично). Представьте, что вы решили обратиться к несуществующему методу этого объекта. Что вы получите? Правильно — фатальную ошибку! Ниже привожу простейший код.
<?php
class OurClass{}
$Object=new OurClass;
// Получаем Fatal error: Call to undefined method OurClass::DynamicMethod()
$Object->DynamicMethod();
?>
<?php
class OurClass{}
// Получаем Fatal error: Call to undefined method OurClass::StaticMethod()
OurClass::StaticMethod();
?>
Так вот, иногда возникает необходимость либо выполнить какой-то код при отсутствии нужного нам метода, либо узнать какой метод пытались вызвать, либо использовать другое API для вызова нужного нам метода. С этой целью и существуют методы __call() и __callStatic() — они перехватывают обращение к несуществующему методу в контексте объекта и в статическом контексте, соответственно.
Перепишем наши примеры с использованием «магических методов». Примечание: Каждый из этих волшебников принимает два параметра: первый — имя метода, который мы пытаемся вызвать, второй — список, содержащий параметры вызываемого метода. Ключ — номер параметра вызываемого метода, значение — собственно сам параметр
<?php
class OurClass
{
public function __call($name,array $params)
{
echo 'Вы хотели вызвать $Object->'.$name.', но его не существует, и сейчас выполняется '.__METHOD__.'()<br>'
.PHP_EOL;
return;
}
public static function __callStatic($name,array $params)
{
echo 'Вы хотели вызвать '.__CLASS__.'::'.$name.', но его не существует, и сейчас выполняется '.__METHOD__.'()';
return;
}
}
$Object=new OurClass;
#Вы хотели вызвать $Object->DynamicMethod, но его не существует, и сейчас выполняется OurClass::__call()
$Object->DynamicMethod();
#Вы хотели вызвать OurClass::StaticMethod, но его не существует, и сейчас выполняется OurClass::__callStatic()
OurClass::StaticMethod();
?>
Практическое применение этих двух товарищей зависит только от вашей фантазии. В качестве примера, приведу набросок-реализации техники программирования Fluent Interface (некоторые считают это паттерном проектирования, но от названия суть не меняется). Коротко говоря, fluent interface позволяет составлять цепочки вызовов объектов (с виду что-то похожее на jQuery). На хабре есть пару статей про реализацию такого рода алгоритмов. На ломаном русском переводе fluent interfaces звучат как «текучие интерфейсы»
<?php
abstract class Manager
{
public
$content_storage='';
public function __toString()
{
return $this->content_storage;
}
public function __call($name,array $params)
{
$this->content_storage.=$this->_GetObject($name,$params).'<br>'.PHP_EOL;
return $this;
}
}
abstract class EntryClass
{
public static function Launch()
{
return new FluentInterface;
}
}
class FluentInterface extends Manager
{
public function __construct()
{
/**
* Что-нибудь инициализируем
*/
}
public static function _GetObject($n,array $params)
{
return $n;
}
}
echo $FI=EntryClass::Launch()
->First()
->Second()
->Third();
/*
Выведет
First
Second
Third
*/
?>