1

考虑这个类的安排——特别是魔术函数 __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

发生什么了?我不喜欢这种解决方法 - 它不时尚。我需要它以这种方式工作:

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

请帮忙?:-)

4

4 回答 4

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 上都可以工作,那么您应该始终使用大括号明确定义您希望它如何工作,无论没有它们,您的代码是否适合您。

PHP 7.0 升级说明中有一些关于此更改的文档,尽管给出的示例并未涵盖您的确切情况。

于 2018-10-12T12:13:55.190 回答
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);
    }

}
于 2018-10-12T11:52:09.433 回答
0

Thank you for the responses. I devised a cute workaround as follows:

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

Usage:

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

How it works? Foo->myBar becomes private (Foo->$_myBar);

we create a public function with the name myBar inside Foo;

we create a "getBarman" fuction inside Bar which is called from Foo->myBar('john')

A few more steps - and now there's no ambiguity - Foo->myBar() IS always a function.

Cheers

M

于 2018-10-13T21:18:22.853 回答
0

我相信你可以在它周围添加大括号:

$company = new Foo();
$drink = ($company->myBar)('john')->makeDrink();
echo $drink; // vodka martini, shaken
于 2020-04-14T08:51:07.350 回答