PHP5.3: ошибка вызова неопределенного метода при вызове вызова из переменной класса

Я проводил некоторые тесты (для замены старого кода) с помощью магического метода __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) для «переадресации» вызова с использованием call_user_func_array, но это не элегантно.

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

Обновлять:

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

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

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

person lepe    schedule 24.06.2010    source источник
comment
Пожалуйста, предоставьте полный пример кода, который показывает вашу проблему. Пример кода, который, как вы говорите, работает, не работает, а пример кода, который, как вы говорите, создает проблему, работает.   -  person Sjoerd    schedule 24.06.2010
comment
Да, извините, мой плохой... Я обновляю его. Sjoerd: Этот пример сработал для вас? странно :С   -  person lepe    schedule 24.06.2010


Ответы (4)


Когда вы делаете $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();
person Gordon    schedule 24.06.2010
comment
Мы отправили сообщение одновременно... Да, возможно, это могло бы помочь... Если я не найду другой лучшей альтернативы, я отмечу ваш ответ как хороший. - person lepe; 24.06.2010

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

$t->k(4, 5)

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

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

См. также ошибку №50029, в которой описана ваша проблема.

person Sjoerd    schedule 24.06.2010
comment
(+1). Теперь мне становится ясно. Спасибо за ссылку. - person lepe; 24.06.2010

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

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

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

person StasM    schedule 24.06.2010

Если вы вызовете $test->k(), PHP будет искать метод с именем «k» в экземпляре $test и, очевидно, выдаст исключение.

Чтобы решить эту проблему, вы можете создать геттер свойства "k"

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.
    }

    public function getK() {
        return $this->k;
    }
}

Итак, теперь вы можете использовать функтор следующим образом:

$t = new Test();
echo $t->getK()(4,5);
person David Ginanni    schedule 16.10.2019