代码之家  ›  专栏  ›  技术社区  ›  Tyler Carter

PHP中的lambda函数不符合逻辑

  •  13
  • Tyler Carter  · 技术社区  · 15 年前

    注释 :我已经将这篇文章浓缩到我的个人维基中: http://wiki.chacha102.com/Lambda 享受

    在PHP中,lambda样式的函数有一些问题。

    首先,这项工作:

    $foo = function(){ echo "bar"; };
    $foo();
    

    第二,这项工作:

    class Bar{
        public function foo(){
           echo "Bar";
        }
    

    第三,这项工作:

    $foo = new stdClass;
    $foo->bar = function(){ echo "bar"; };
    $test = $foo->bar;
    $test();
    

    但是,这不起作用:

    $foo = new stdClass;
    $foo->bar = function(){ echo "bar"; };
    $foo->bar();
    

    而且,这不起作用

    class Bar{
        public function foo(){
           echo "Bar";
        }
    $foo = new Bar;
    $foo->foo = function(){ echo "foo"; };
    $foo->foo(); // echo's bar instead of Foo.
    

    我的问题是 为什么? 以及如何保证:

    $foo->bar = function(){ echo "test"; };
    $foo->bar();
    

    而这

    $foo = new Bar;
    $foo->bar();
    

    是否正确调用?如果您可以指向说明此问题发生原因的文档,则需要额外的要点。

    7 回复  |  直到 13 年前
        1
  •  9
  •   cletus    15 年前

    这是一个有趣的问题。这工作:

    $a = new stdClass;
    $a->foo = function() { echo "bar"; };
    $b = $a->foo;
    $b(); // echos bars
    

    但正如你所说,这并不是:

    $a = new stdClass;
    $a->foo = function() { echo "bar"; };
    $a->foo();
    

    如果要动态调用成员的对象,请尝试:

    class A {
      public function __call($func, $args) {
        $f = $this->$func;
        if (is_callable($f)) {
          return call_user_func_array($f, $args);
        }
      }
    }
    
    $a = new A;
    $a->foo = function() { echo "bar\n"; };
    $a->foo2 = function($args) { print_r($args); };
    $a->foo();
    $a->foo2(array(1 => 2, 3 => 4));
    

    但是不能用这种方式替换可调用方法,因为 __call() 只对不存在或不可访问的方法(例如它们是私有的)调用。

        2
  •  3
  •   Ignacio Vazquez-Abrams    15 年前

    函数和方法在PHP中的处理方式不同。你可以使用 runkit_method_add() 向类中添加方法,但我不知道向实例中添加方法的方法。

        3
  •  1
  •   Alix Axel    15 年前

    有趣的问题,尽管我看不出为什么这会奏效:

    class Bar{
        public function foo(){
           echo "Bar";
        }
    $foo = new Bar;
    $foo->foo = function(){ echo "foo"; };
    $foo->foo(); // echo's bar instead of Foo.
    

    我也有类似的问题 __invoke() 我也没能解决:

    class base {
        function __construct() {
            $this->sub = new sub();
        }
    
        function __call($m, $a) {
        }
    }
    
    class sub {
        function __invoke($a) {
        }
    }
    
    $b = new base();
    $b->sub('test'); // should trigger base::__call('sub', 'test') or sub::__invoke('test')?
    

    解决方案?从不使用 y-调用() !P

        4
  •  1
  •   NullUserException Mark Roddy    13 年前

    最接近实现这一目标的方法是 __call 重载以检查属性是否包含闭包:

    class what {
      function __call($name, $args) {
        $f= $this->$name;
        if ($f instanceof Closure) {
          $f();
        }
      }
    }
    
    $foo = new what();
    $foo->bar = function(){ echo "bar"; };
    $foo->bar();
    

    尽管要记住文档中的以下注释:

    匿名函数当前 使用闭包类实现。 这是一个实现细节, 不应该依赖。

    参考文献: Anonymous functions

        5
  •  1
  •   Alfred redcoder    13 年前

    OP已经提出了解决方案:

    $foo = new stdClass;
    $foo->bar = function(){ echo "bar"; };
    $test = $foo->bar;
    $test();
    

    也就是说,任何包含anon函数的属性都具有固有的歧义,因为在属性名后添加括号会告诉PHP您正在调用方法,而不是在属性中调用anon函数。要解决这种歧义,必须先将属性存储到局部变量中,然后调用anon函数,从而添加一定程度的分离。

    您只需将类属性视为一个属性而不是“一个可作为方法调用的属性”,不管它的内容是什么,并且假设如果您在属性后面加上括号,PHP将查找一个真正的类方法。

        6
  •  0
  •   Natalie Adams    15 年前

    在我看来,这就像一只虫子,而不是一个“怪癖”:

    <?php
    $t = new stdClass;
    $t->a = function() { echo "123"; };
    var_dump($t);
    echo "<br><br>";
    $x = (array)$t;
    var_dump($x);
    echo "<br><br>";
    $x["a"]();
    echo "<br><br>";
    ?>
    

    object(stdClass)#1 (1) { ["a"]=> object(Closure)#2 (0) { } } 
    
    array(1) { ["a"]=> object(Closure)#2 (0) { } } 
    
    123
    

    就在那里,我只是觉得PHP不知道如何运行它。

        7
  •  0
  •   erisco    15 年前

    考虑一下:

    <?php
    
    class A {
    
        public $foo
    
        public function foo() {
            return 'The method foo';
        }
    
    }
    
    $obj = new A;
    $obj->foo = function() { return 'The closure foo'; };
    
    var_dump($obj->foo());
    

    您的意思是$obj->foo()闭包还是$obj->foo()方法?它是不明确的,PHP决定您指的是这个方法。要使用闭包,你必须消除你的意思。实现这一点的一种方法是像以前那样使用临时变量。另一种方法是 call_user_func($obj->foo) .

    我不知道还有什么别的容易的方法。