【问题标题】:Cannot assign a closure in a stdClass property in php无法在 php 的 stdClass 属性中分配闭包
【发布时间】:2019-06-20 22:49:32
【问题描述】:

我正在尝试使用闭包编写类似 js 的 php。但是,我不明白为什么我不能将闭包分配给 stdClass 属性。

代码自行解释:

$sum = function ($a, $b) {return $a + $b;};
echo $sum(11, 11);
// prints 22



$arr = [];
$arr['sum'] = function ($a, $b) {return $a + $b;};
echo $arr['sum'](22, 22);
// prints 44



$cl = new stdClass;
$cl->sum = function ($a, $b) {return $a + $b;};
echo $cl->sum(33, 33);
// Fatal error: Uncaught Error: Call to undefined method stdClass::sum()



# although I can't think of any use cases for this
class Custom {
    public $sum = NULL;

    function __construc() {
        $this->sum = function ($a, $b) {return $a + $b;};
    }
}

$custom = new Custom;
echo $custom->sum(44, 44);
// Fatal error: Uncaught Error: Call to undefined method Custom::sum()

【问题讨论】:

  • @hanshenrik Idk,这背后可能有与语言实现相关的原因......
  • 作为一种解决方法,您可以创建它而不是 StdObject:$cl = new class {public function __call($name,$args){return call_user_func_array($this->{$name},$args);}}; - 现在您可以这样做 $cl->sum = function ($a, $b) {return $a + $b;}; echo $cl->sum(33, 33); - 但这是个好主意吗?我不知道
  • 我想这就是你要找的东西:stackoverflow.com/questions/4535330/…
  • @Nouphal.M 没有一个关于 4535330 的答案解释了为什么这些变通办法是必要的。很多答案都有很多不同的解决方法,但没有解释为什么普通的旧 $o=new StdClass;$o->f=function(){};$o->f(); 不起作用。

标签: php closures


【解决方案1】:

只需将属性名称括在圆括号中即可。

echo ($cl->sum)(33, 33);
echo ($custom->sum)(44, 44);

3v4l 示例:

https://3v4l.org/3ZqNV

基于 cmets 编辑:

Javascript 中的对象只能有属性。此属性可以是原始值、其他对象或函数,但属性的名称是唯一的,尽管它的内容。

在 PHP 中,一个对象可以同时具有属性和方法。

假设我们有以下代码:

class MyClass 
{

    public $foo;

    public function __construct() 
    {
        $this->foo = function(int $a, int $b): int {
            return $a * $b;
        };
    }

    public function foo(int $a, int $b): int 
    {
        return $a + $b;
    }
}

$myClass = new MyClass();

echo $myClass->foo(2, 3);

foo 属性和foo 方法签名相同,但程序员的意愿是什么?

此代码将调用方法foo 并打印5,因此任何行$var->name() 都被解释为方法调用。

如果你想在属性内调用闭包,你必须使用不同的语法,这样才不会产生歧义。

echo ($myClass->foo)(2, 3) //Prints 6

https://3v4l.org/PXiMQ

【讨论】:

  • 这提供了一种解决方法,但它没有解释为什么 $cl->sum(33, 33); 不起作用
  • 你的类没有名为 sum 的方法。这就是在 PHP 中调用存储在对象属性中的闭包的方式。
【解决方案2】:

您可以使用闭包方法bind()bindTo()call()

$cl = new stdClass;
$sum = function ($a, $b) {return $a + $b;};
Closure::bind($sum, $cl);

echo $sum(33, 33); // this function is now part of the class. 

如果您希望扩展此功能,您可以在类中创建一个注册函数,该函数依赖于诸如 __call() 之类的魔术方法来检查该方法是否存在,如果存在则在内部调用注册的闭包。

【讨论】:

  • 这提供了一种解决方法,但它没有解释为什么 $cl->sum(33, 33); 不起作用
  • 嗯,答案已经给出了。但是,该功能取决于您运行的 PHP 版本。是的,如果您已经在运行 PHP7,这是一种解决方法(我不能 100% 确定此语句,因为括号优先级在一定程度上发生了变化),但如果不是,这可以解决问题。
猜你喜欢
  • 2011-07-27
  • 1970-01-01
  • 2017-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多