web-dev-qa-db-fra.com

PHP 5.4 - 'fermeture $ ce support'

Je vois que les nouvelles fonctionnalités prévues pour PHP 5.4 sont: les traits, le déréférencement de tableaux, une interface JsonSerializable et quelque chose appelé 'closure $this support '

http://en.wikipedia.org/wiki/Php#Release_history

Alors que les autres sont soit immédiatement clairs (JsonSerialiable, déréférencement de tableau) ou j'ai recherché les spécificités (traits), je ne suis pas sûr de ce qu'est la "fermeture de ce support". J'ai échoué sur Google ou trouvé quelque chose à ce sujet sur php.net

Quelqu'un sait-il ce que c'est censé être?

Si je devais deviner, cela signifierait quelque chose comme ceci:

$a = 10; $b = 'strrrring';
//'old' way, PHP 5.3.x
$myClosure = function($x) use($a,$b)
             {
                 if (strlen($x) <= $a) return $x;
                 else return $b;
             };

//'new' way with closure $this for PHP 5.4
$myNewClosure = function($x) use($a as $lengthCap,$b as $alternative)
                 {
                     if(strlen($x) <=  $this->lengthCap)) return $x;
                     else 
                     {
                         $this->lengthCap++;  //lengthcap is incremented for next time around
                         return $this->alternative;
                     }
                 };

La signification (même si cet exemple est trivial) est que dans le passé, une fois la fermeture construite, les variables liées à l'utilisation sont fixées. Avec "fermeture $ ce support", ils ressemblent plus à des membres avec lesquels vous pouvez jouer.

Ce son est-il correct et/ou proche et/ou raisonnable? Est-ce que quelqu'un sait ce que signifie cette "fermeture $ ce soutien"?

68
jon_darkstar

Cela était déjà prévu pour PHP 5.3, mais

Pour PHP 5.3 $, cette prise en charge des fermetures a été supprimée car aucun consensus n'a pu être atteint sur la façon de l'implémenter de manière saine. Ce RFC décrit les routes possibles qui peuvent être prises pour l'implémenter dans le prochain PHP version.

Cela signifie en effet que vous pouvez vous référer à l'instance d'objet ( démo en direct )

<?php
class A {
  private $value = 1;
  public function getClosure() 
  {
    return function() { return $this->value; };
  }
}

$a = new A;
$fn = $a->getClosure();
echo $fn(); // 1

Pour une discussion, voir le PHP Wiki

et pour un intérêt historique:

74
Gordon

Une chose que Gordon a ratée est la reliure de $this. Bien que ce qu'il ait décrit soit le comportement par défaut, il est possible de le lier à nouveau.

Exemple

class A {
    public $foo = 'foo';
    private $bar = 'bar';

    public function getClosure() {
        return function ($prop) {
            return $this->$prop;
        };
    }
}

class B {
    public $foo = 'baz';
    private $bar = 'bazinga';
}

$a = new A();
$f = $a->getClosure();
var_dump($f('foo')); // prints foo
var_dump($f('bar')); // works! prints bar

$b = new B();
$f2 = $f->bindTo($b);
var_dump($f2('foo')); // prints baz
var_dump($f2('bar')); // error

$f3 = $f->bindTo($b, $b);
var_dump($f3('bar')); // works! prints bazinga

Les fermetures bindTo méthode d'instance (utilisez alternativement la statique Closure::bind) renverra une nouvelle fermeture avec $this re-lié à la valeur donnée. La portée est définie en passant le deuxième argument, cela déterminera la visibilité des membres privés et protégés, lorsqu'ils sont accessibles depuis l'intérieur de la fermeture.

53
igorw

En s'appuyant sur la réponse de @ Gordon, il est possible d'imiter certains aspects hacky de la fermeture - $ this en PHP 5.3.

<?php
class A
{
    public $value = 12;
    public function getClosure()
    {
        $self = $this;
        return function() use($self)
        {
            return $self->value;
        };
    }
}

$a = new A;
$fn = $a->getClosure();
echo $fn(); // 12
22
Xeoncross

Sur la base des autres réponses ici, je pense que cet exemple montrera ce qui est possible PHP 5.4+:

<?php

class Mailer {
    public    $publicVar    = 'Goodbye ';
    protected $protectedVar = 'Josie ';
    private   $privateVar   = 'I love CORNFLAKES';

    public function mail($t, $closure) {
        var_dump($t, $closure());
    }
}

class SendsMail {
    public    $publicVar    = 'Hello ';
    protected $protectedVar = 'Martin ';
    private   $privateVar   = 'I love EGGS';

    public function aMailingMethod() {
        $mailer = new Mailer();
        $mailer->mail(
            $this->publicVar . $this->protectedVar . $this->privateVar,
            function() {
                 return $this->publicVar . $this->protectedVar . $this->privateVar;
            }
        );
    }
}

$sendsMail = new SendsMail();
$sendsMail->aMailingMethod();

// prints:
// string(24) "Hello Martin I love EGGS"
// string(24) "Hello Martin I love EGGS"

voir: https://eval.in/private/3183e0949dd2db

2