Не всё работает так, как заявлено в документации
Те, кто хорошо знают PHP5, наверняка знакомы или хотя бы раз использовали такой мощный инструмент, как магические методы.
Один из методов, __call()
, согласно документации используется при попытке вызова недоступного метода в контексте объекта.
Иными словами, в следующем фрагменте кода
class A {
public function call($method, $params)
{
print "Attempt to call {$method}\n";
}
}
$a = new A();
$a->someMethod();
?>
будет вызван магический метод A::__call("someMethod", array())
, который напечатает
С несуществующими методами всё ясно, но в документации упоминается слово «недоступные» (inaccessible).
А с недоступными методами, к сожалению, не всё так гладко. Рассмотрим пример:
class A {
public function get()
{
return array(&$this, 'test');
}
public function __call($method, $params)
{
if (true == method_exists($this, $method)) {
call_user_func_array(array(&$this, $method), $params);
}
}
protected function test()
{
echo "It makes me money and that's all right\n";
}
}
$a = new A();
$callback = $a->get();
call_user_func($callback);
?>
Метод A::test()
является доступным в контексте класса A
, но недоступным в контексте объекта $a
. Следуя документации, ожидаемым результатом был бы вызов A::test()
из A::__call()
. Но в действительности всё не так, как на самом деле:
А метод __call()
даже не вызывается.
В принципе, я не обратил бы на это внимание, если бы магические методы __get()
/__set()
/__isset()
/__unset()
работали точно так же. Но я знаю, что это не так:
class A
{
private $x;
public function __get($name)
{
print $name . "\n";
return null;
}
}
$a = new A();
$a->x;
?>
В этом случае, хотя $a->x
и недоступен в контексте объекта $a
, метод A::__get()
будет вызван.
Я не знаю, считать ли политику (не)вызова __call()
в PHP ошибкой или нет, ясно одно: подобное поведение не согласуется с политикой вызовов других магических методов.
Исправлено в PHP 5.3