代码之家  ›  专栏  ›  技术社区  ›  empy26

PHP绑定方法到另一个类

  •  7
  • empy26  · 技术社区  · 8 年前

    P、 这不是一个实用的问题,只是想知道将非静态方法绑定到另一个类是真的吗

    class Foo {
    
        public $text = 'Hello World!';
    
        public function say() {
            echo $this->text;
        }
    
    }
    
    class Bar {
    
        public $text = 'Bye World!';
    
        public function __call($name, $arguments) {
            $test = Closure::fromCallable(array(new Foo, 'say'));
            $res = Closure::bind($test, $this);
            return $res();
        }
    
    }
    
    $bar = new Bar();
    $bar->say();
    

    下面的代码可以正常工作

     function say(){
        echo $this->text;
     }
     class Bar {
    
        public $text = 'Bye World!';
    
        public function __call($name, $arguments) {
            $test = Closure::fromCallable('say');
            $res = Closure::bind($test, $this);
            return $res();
        }
    
    }
    
    $bar = new Bar();
    $bar->say();
    
    2 回复  |  直到 8 年前
        1
  •  5
  •   revo shanwije    8 年前

    目前不支持此操作。如果要将闭包绑定到新对象,它不能是假闭包,或者新对象必须与旧对象兼容( source ).

    那么,什么是 假闭合 :A Closure::fromCallable .

    这意味着,您有两种解决问题的方法:

    1. Bar 必须与类型兼容 Foo -所以只要做 酒吧 扩展自 傅 ,如果可能的话。

    2. 使用未绑定函数,如annonymous、static或类外函数。

        2
  •  0
  •   rela589n    4 年前

    PHP不支持它。然而,在PHP 7.0中,这是有点可能的。考虑这个例子:

    class Foo {
        private $baz = 1;
        
        public function baz() {
            var_dump('Foo');
            var_dump($this->baz);
        }
    }
    
    
    class Bar {
        public $baz = 2;
        
        public function baz() {
            var_dump('Bar');
            var_dump($this->baz);
        }
    }
    
    
    $fooClass = new ReflectionClass('Foo');
    $method = $fooClass->getMethod('baz');
    
    $foo = new Foo;
    $bar = new Bar;
    
    $closure = $method->getClosure($foo);
    
    $closure2 = $closure->bindTo($bar);
    
    $closure2();
    

    string(3) "Foo"
    int(2)
    

    这意味着方法 Foo::baz 对对象调用了 $bar 并已访问其 $baz 财产而不是 Foo::$baz

    另外,请注意 Bar::$baz 是公共财产。如果它是私有的,php会抛出致命错误,无法访问私有属性。这可以通过改变关闭范围来解决 $closure->bindTo($bar, $bar); 然而,在php7.0中已经禁止这样做,并将导致以下警告: Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure() .

    然而,还有解决办法 ,这将适用于最新版本的php。拉雷维尔创造了一个很棒的软件包,名为 laravel/serializable-closure . 它所做的很简单——它读取闭包的源代码,以便将其序列化,并能够在以后使用所有必要的上下文将其取消序列化。

    因此,基本上,未序列化闭包的功能保持不变,但与PHP的观点不同。PHP不知道它是从类方法创建的,因此允许绑定任何 $this .

    最终变体如下所示:

    $callback = [$foo, 'baz'];
    
    $closure = unserialize(
        serialize(new SerializableClosure(Closure::fromCallable($callback)))
    )->getClosure();
    
    $closure->call($bar);
    

    推荐文章