Рассмотрим это расположение классов — и, в частности, магическую функцию __invoke:
class Barman {
public function __construct() {
// .. .constructor stuff - whatever
}
public function makeDrink() {
return "vodka martini, shaken";
}
}
class Bar {
private $arr_barmen = array();
public function __construct() {
$this->arr_barmen['john'] = new Barman();
}
public function __invoke($barman_id) {
echo "I have been invoked";
return $this->arr_barmen[$barman_id];
}
public function aBarFunc($param) {
return "yes it worked ," .$param;
}
}
class Foo {
public $myBar;
public function __construct() {
$this->myBar = new Bar();
}
}
Я хочу написать такой синтаксис
$company = new Foo();
$company->myBar('john')->makeDrink();
Предпочтительный результат:
«водка мартини, шейк»
Фактический результат:
«Вызов неопределенного метода Foo :: myBar ()»
Вызов myBar () с помощью магического метода должен вернуть объект бармена, для которого вы можете вызвать любой из открытых методов бармена.
Но теперь рассмотрим это (что работает)
$company = new Foo();
$myBar = $company->myBar;
$drink = $myBar('john')->makeDrink();
echo $drink;
// Result:
// I have been invoked
// vodka martini, shaken
Так, что происходит? Мне не нравится этот обходной путь — он не гладкий.
Мне нужно, чтобы это работало так:
$ Компани> myBar ( ‘Джон’) -> makeDrink ();
Пожалуйста помоги? 🙂
Для достижения цепочки вы должны вернуть объект Barman в invoke.
class Barman {
public function __construct() {
// .. .constructor stuff - whatever
}
public function makeDrink() {
return "vodka martini, shaken";
}
}
class Bar {
private $arr_barmen = array();
public function __construct() {
$this->arr_barmen['john'] = new Barman();
}
public function __invoke($barman_id) {
echo "I have been invoked";
return $this->arr_barmen[$barman_id] = new Barman();
}
public function aBarFunc($param) {
return "yes it worked ," . $param;
}
}
class Foo {
public $myBar;
public function __construct() {
$this->myBar = new Bar();
}
// create a function with variable name to invoke the object
public function myBar($name) {
$mybar = $this->myBar;
return $mybar($name);
}
}
Это вызвано двусмысленностью звонка, который вы пытаетесь сделать:
$company->myBar('john')->makeDrink();
Так как myBar
это свойство, интерпретатор PHP не ожидает его вызова. Это анализирует как попытку вызвать метод myBar()
который не существует, и, следовательно, выдает ошибку.
Прямой способ решить эту проблему — прояснить неоднозначность для переводчика. Это можно сделать, добавив фигурные скобки вокруг свойства следующим образом:
$company->{myBar}('john')->makeDrink();
Код теперь явно myBar
является свойством и должно быть доступно как таковое, но оно содержит значение, которое можно вызвать, и которое вы хотите сделать этот вызов.
Вся эта тема усложняется (немного) тем фактом, что PHP 5.x и PHP 7.x ведут себя по-разному в отношении того, как они по умолчанию обрабатывают такие неоднозначности. PHP 7 изменил значения по умолчанию, чтобы исправить некоторые внутренние несоответствия в языке. В результате в таких ситуациях, когда возникает неоднозначность, если вы хотите, чтобы ваш код работал как на PHP 5.x, так и на 7.x, вы всегда должны использовать фигурные скобки, чтобы явно определить, как вы хотите, чтобы он работал, независимо от работает ли ваш код у вас без них.
Есть некоторая документация об этом изменении в примечания по обновлению PHP 7.0, хотя приведенные примеры не охватывают вашу точную ситуацию.
Спасибо за ответы. Я разработал симпатичный обходной путь следующим образом:
class Barman {
public function __construct() {
}
public function makeDrink() {
return "vodka martini, shaken";
}
}
class Bar {
private $arr_barmen = array();
public function __construct() {
$this->arr_barmen['john'] = new Barman();
}
public function getBarman($barman_id) {
return $this->arr_barmen[$barman_id];
}
public function __invoke($barman_id) {
echo "I have been invoked \n";
return $this->arr_barmen[$barman_id];
}
}
class Foo {
private $_myBar;
public function __construct() {
$this->_myBar = new Bar();
}
// The fix
public function myBar($barman_id) {
return $this->_myBar->getBarman($barman_id);
}
}
Использование:
$company = new Foo();
$drink = $company->myBar('john')->makeDrink();
echo $drink; // vodka martini, shaken
Как это устроено?
Foo-> myBar становится приватным (Foo -> $ _ myBar);
внутри Foo мы создаем публичную функцию с именем myBar;
мы создаем функцию getBarman внутри Bar, которая вызывается из Foo-> myBar (‘john’)
Еще несколько шагов — и теперь нет никакой двусмысленности — Foo-> myBar () всегда является функцией.
ура
M