Closure::bindTo

(PHP 5 >= 5.4.0, PHP 7, PHP 8)

Closure::bindTo Duplica a closure com um novo objeto vinculado e escopo de classe.

Descrição

public Closure::bindTo(?object $newThis, object|string|null $newScope = "static"): ?Closure

Cria e retorna uma nova função anônima com o mesmo corpo e mesmas variáveis ligadas como a original, mas possivelmente com um diferente objeto ligado e um novo escopo de classe.

O “obeto ligado” determina o valor que $this terá no corpo da função e o “escopo de classe” representa uma classe que determina quais membros privados e protegidos a função anônima será capaz de acessar. Nomeadamente, os membros que estarão visíveis serão os mesmos que estariam, se a função anônima fosse um método da classe informada como valor do parâmetro newScope.

Closures estáticas não podem ter nenhum objeto ligado (o valor do parâmetro newThis deveria ser null), mas este método pode entretanto ser utilizada para alterar seus escopos de classe.

Este método vai assegurar que, para uma closure não estática, possuir uma instância ligada irá implicar em ter escopo definido e vice-versa. Para este fim, closures não estáticas que recebem um escopo com instância null são tornadas estáticas; e closures não estáticas sem escopo que recebem uma instância não nula têm o escopo definido para uma classe não especificada.

Nota:

Se for requerido duplicar as funções anônimas, pode ser utilizada clonagem alternativamente.

Parâmetros

newThis

O objeto ao qual a função anônima informada deve ser ligada, ou null para que a closure seja não ligada.

newScope

O escopo de classe ao qual a closure deve ser associada, ou 'static' para manter a atual. Se um objeto for informado, o tipo do objeto será usado no lugar. Isto determina a visibilidade de métodos protegidos e privados do objeto ligado. Não é permitido passar (um objeto de) uma classe interna neste parâmetro.

Valor Retornado

Retorna o novo objeto Closure criado ou null em caso de falha.

Exemplos

Exemplo #1 Exemplo de Closure::bindTo()

<?php

class A
{
private
$val;

public function
__construct($val)
{
$this->val = $val;
}

public function
getClosure()
{
// Retorna a closure ligada a este objeto e escopo
return function() {
return
$this->val;
};
}
}

$ob1 = new A(1);
$ob2 = new A(2);

$cl = $ob1->getClosure();
echo
$cl(), "\n";

$cl = $cl->bindTo($ob2);
echo
$cl(), "\n";

?>

O exemplo acima produzirá algo semelhante a:

1
2

Veja Também

adicione uma nota

Notas Enviadas por Usuários (em inglês) 8 notes

up
43
Nezar Fadle
10 years ago
We can use the concept of bindTo to write a very small Template Engine:#############index.php############<?phpclass Article{    private $title = "This is an article";}class Post{    private $title = "This is a post";}class Template{    function render($context, $tpl){        $closure = function($tpl){            ob_start();            include $tpl;            return ob_end_flush();        };        $closure = $closure->bindTo($context, $context);        $closure($tpl);    }}$art = new Article();$post = new Post();$template = new Template();$template->render($art, 'tpl.php');$template->render($post, 'tpl.php');?>#############tpl.php############<h1><?php echo $this->title;?></h1>
up
36
tatarynowicz at gmail dot com
12 years ago
You can do pretty Javascript-like things with objects using closure binding:<?phptrait DynamicDefinition {        public function __call($name, $args) {        if (is_callable($this->$name)) {            return call_user_func($this->$name, $args);        }        else {            throw new \RuntimeException("Method {$name} does not exist");        }    }        public function __set($name, $value) {        $this->$name = is_callable($value)?             $value->bindTo($this, $this):             $value;    }}class Foo {    use DynamicDefinition;    private $privateValue = 'I am private';}$foo = new Foo;$foo->bar = function() {    return $this->privateValue;};// prints 'I am private'print $foo->bar();?>
up
20
safakozpinar at gmail dot com
13 years ago
Private/protected members are accessible if you set the "newscope" argument (as the manual says).<?php$fn = function(){    return ++$this->foo; // increase the value};class Bar{    private $foo = 1; // initial value}$bar = new Bar();$fn1 = $fn->bindTo($bar, 'Bar'); // specify class name$fn2 = $fn->bindTo($bar,  $bar); // or objectecho $fn1(); // 2echo $fn2(); // 3
up
5
Anonymous
7 years ago
If you want to unbind completely the closure and the scope you need to set both to null:<?phpclass MyClass{    public $foo = 'a';    protected $bar = 'b';    private $baz = 'c';    /**     * @return array     */    public function toArray()    {        // Only public variables        return (function ($obj) {            return get_object_vars($obj);        })->bindTo(null, null)($this);    }}?>In this example, only the public variables of the class are exported (foo).If you use the default scope (->bindTo(null)) also protected and private variables are exported (foo, bar and baz).It was hard to figure it out because there is nowhere mentioned in the documentation that you can use null as a scope.
up
3
luc at s dot illi dot be
9 years ago
Access private members of parent classes; playing with the scopes:<?PHPclass Grandparents{ private $__status1 = 'married'; }class Parents extends Grandparents{ private $__status2 = 'divorced'; }class Me extends Parents{ private $__status3 = 'single'; }$status1_3 = function(){    $this->__status1 = 'happy';    $this->__status2 = 'happy';    $this->__status3 = 'happy';};$status1_2 = function(){    $this->__status1 = 'happy';    $this->__status2 = 'happy';};// test 1:$c = $status1_3->bindTo($R = new Me, Parents::class);            #$c();    // Fatal: Cannot access private property Me::$__status3// test 2:$d = $status1_2->bindTo($R = new Me, Parents::class);$d();var_dump($R);/*object(Me)#5 (4) {  ["__status3":"Me":private]=>  string(6) "single"  ["__status2":"Parents":private]=>  string(5) "happy"  ["__status1":"Grandparents":private]=>  string(7) "married"  ["__status1"]=>  string(5) "happy"}*/// test 3:$e = $status1_3->bindTo($R = new Me, Grandparents::class);    #$e(); // Fatal: Cannot access private property Me::$__status3// test 4:$f = $status1_2->bindTo($R = new Me, Grandparents::class);    $f();var_dump($R);/*object(Me)#9 (4) {  ["__status3":"Me":private]=>  string(6) "single"  ["__status2":"Parents":private]=>  string(8) "divorced"  ["__status1":"Grandparents":private]=>  string(5) "happy"  ["__status2"]=>  string(5) "happy"}*/?>Clear the stack trace:<?PHPuse Exception;use ReflectionException;$c = function(){    $this->trace = [];};$c = $c->bindTo($R = new ReflectionException, Exception::class);$c();try{    throw $R;}catch(ReflectionException $R){    var_dump($R->getTrace());}/*array(0) {}*/?>
up
8
amica at php-resource dot de
13 years ago
With rebindable $this at hand it's possible to do evil stuff:<?php    class A {        private $a = 12;        private function getA () {            return $this->a;        }    }    class B {        private $b = 34;        private function getB () {            return $this->b;        }    }    $a = new A();    $b = new B();    $c = function () {        if (property_exists($this, "a") && method_exists($this, "getA")) {            $this->a++;            return $this->getA();        }        if (property_exists($this, "b") && method_exists($this, "getB")) {            $this->b++;            return $this->getB();        }    };    $ca = $c->bindTo($a, $a);    $cb = $c->bindTo($b, $b);    echo $ca(), "\n"; // => 13    echo $cb(), "\n"; // => 35?>
up
0
malferov at gmail dot com
1 year ago
If you, like me, did not immediately understand what exactly "(an object of) an internal class" in the documentation about the 'newScope' parameter:

By an internal class, the documentation means any internal PHP class such as 'stdClass', 'Closure', 'WeakMap', and etc:

<?php

class A {}
$a = new A();
$closure = fn() => null;

$binded = $closure->bindTo($a, 'stdClass',); // Cannot bind closure to scope of internal class stdClass
$binded = $closure->bindTo($a, $closure,); // Warning: Cannot bind closure to scope of internal class Closure etc.
up
0
Olexandr Kalaidzhy
3 years ago
Get all object vars without using Reflection:<?phpdeclare(strict_types=1);class A{    private $foo = 'foo';    protected $bar = 'bar';    public $buz = 'buz';}function get_object_vars_all($object): array{    if (!\is_object($object)) {        throw new \InvalidArgumentException(sprintf('The argument should be an object, "%s" given.', get_debug_type($object)));    }    $closure = function () {        return get_object_vars($this);    };    return $closure->bindTo($object, $object)();}$a = new A();var_dump(get_object_vars($a));var_dump(get_object_vars_all($a));?>The output: array(1) {  ["buz"]=>  string(3) "buz"}array(3) {  ["foo"]=>  string(3) "foo"  ["bar"]=>  string(3) "bar"  ["buz"]=>  string(3) "buz"}
To Top