PHP5.3: ошибка «Вызов неопределенного метода» при вызове вызова из переменной класса - PullRequest
6 голосов
/ 24 июня 2010

Я проводил некоторые тесты (чтобы заменить старый код) магическим методом __invoke, и я не уверен, что это ошибка или нет:

Предположим, у нас есть класс:

class Calc {
    function __invoke($a,$b){
        return $a*$b;
    }
}

Следующее возможно и работает без проблем:

$c = new Calc;
$k = $c;
echo $k(4,5); //outputs 20

Однако если я хочу иметь другой класс для хранения экземпляра этого объекта, это не сработает:

class Test {
    public $k;
    function __construct() {
        $c = new Calc;
        $this->k = $c; //Just to show a similar situation than before
        // $this-k = new Calc; produces the same error.
    }
}

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

$t = new Test;
echo $t->k(4,5); //Error: Call to undefined method Test::k()

Я знаю, что «решением» может быть использование функции внутри класса Test (с именем k) для «forward»вызов с использованием call_user_func_array, но это не элегантно.

Мне нужно хранить этот экземпляр внутри общего класса (для целей проектирования) и иметь возможность вызывать его как функцию из других классов ... есть предложения?

Обновление:

Я нашел что-то интересное (по крайней мере, для моих целей):

Если мы присвоим «переменную класса» локальной переменной, она будет работать:

$t = new Test;
$m = $t->k;
echo $m(4,5);

Ответы [ 3 ]

6 голосов
/ 24 июня 2010

PHP думает, что вы хотите вызвать метод k в экземпляре $ t, когда делаете:

$t->k(4, 5)

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

$b = $t->k;
$b(4, 5);

См. Также bug # 50029 , которая описывает вашу проблему.

5 голосов
/ 24 июня 2010

Когда вы делаете $test->k(), PHP думает, что вы вызываете метод для экземпляра $test. Поскольку нет метода с именем k(), PHP генерирует исключение. То, что вы пытаетесь сделать, это заставить PHP возвращать открытое свойство k и вызывать его, но для этого вы должны сначала присвоить k переменной. Это вопрос разыменования.

Вы можете добавить магический __call метод к вашему классу Test, чтобы проверить, существует ли свойство с именем вызываемого метода, и вызвать его вместо этого:

public function __call($method, $args) {
    if(property_exists($this, $method)) {
        $prop = $this->$method;
        return $prop();
    }
}

Я оставляю добавление аргументов к вашему обращению. Вы также можете проверить, если свойство is_callable.

Но в любом случае, тогда вы можете сделать

$test->k();
2 голосов
/ 24 июня 2010

Вы не можете использовать синтаксис метода (например, $ foo-> bar ()) для вызова замыканий или объектов с помощью __invoke, поскольку движок всегда думает, что это вызов метода.Вы можете смоделировать это с помощью __call:

function __call($name, $params) {
  if(is_callable($this->$name)) {
    call_user_func_array($this->$name, $params);
  }
}

, но оно не будет работать как есть.

...