PHP Magic __调用类的对象属性

时间:2018-10-11 12:53:24

标签: php class invoke magic-methods chainability

考虑此类安排-特别是魔术函数__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()”

使用magic方法调用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();

请帮助? :-)

4 个答案:

答案 0 :(得分:1)

要获得链接,必须在调用中返回Barman对象。

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

}

答案 1 :(得分:1)

这是由您要拨打的电话中的模棱两可引起的:

$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上都可以使用,则应该始终使用大括号来明确定义希望其工作的方式,无论如果没有它们,您的代码是否对您有用。

the PHP 7.0 upgrade notes中有一些有关此更改的文档,尽管给出的示例并未涵盖您的确切情况。

答案 2 :(得分: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的公共函数;

我们在Bar内部创建一个“ getBarman”功能,从Foo-> myBar('john')调用

还有几个步骤-现在没有歧义-Foo-> myBar()始终是一个函数。

欢呼

M

答案 3 :(得分:0)

我相信您可以在其周围加上括号:

$company = new Foo();
$drink = ($company->myBar)('john')->makeDrink();
echo $drink; // vodka martini, shaken