PHP Magic __invoke для объекта-свойства класса - PullRequest
0 голосов
/ 11 октября 2018

Рассмотрим это расположение класса - и, в частности, магическую функцию __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();

Предпочтительный результат: "vodka martini, встряхнул "

Фактический результат:
" Вызов неопределенного метода Foo :: myBar () "

Вызов myBar () с помощью магического методадолжен вернуть объект бармена, на котором вы можете вызвать любой из открытых методов бармена

Но теперь рассмотрим это (что работает)

$company = new Foo();
$myBar = $company->myBar;
$drink = $myBar('john')->makeDrink();
echo $drink;

// Result:
// I have been invoked 
// vodka martini, shaken

Итак, что происходит?Мне не нравится этот обходной путь - он не гладкий.Мне нужно, чтобы это работало так:

$ company-> myBar ('john') -> makeDrink ();

Пожалуйста, помогите?: -)

Ответы [ 3 ]

0 голосов
/ 12 октября 2018

Это вызвано неоднозначностью вызова, который вы пытаетесь сделать:

$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 имеется некоторая документация об этом изменении, хотя приведенные примеры не охватывают вашу конкретную ситуацию.

0 голосов
/ 14 октября 2018

Спасибо за ответы.Я разработал милый обходной путь:

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);

мы создаем публичную функцию с именем myBar внутри Foo;

мы создаем функцию "getBarman" внутри Bar, которая вызывается из Foo-> myBar ('john')

Еще несколько шагов - и теперь нет никакой двусмысленности - Foo-> myBar () всегда является функцией.

Приветствия

M

0 голосов
/ 12 октября 2018

Для достижения цепочки вы должны вернуть объект 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);
    }

}
...