PHP 5.4 - 'Schließung $ dieser Unterstützung'


68

Ich sehe, dass die neuen geplanten Funktionen für PHP 5.4 sind: Eigenschaften, Array-Dereferenzierung, eine JsonSerializable-Schnittstelle und etwas, das als ' closure $this support' bezeichnet wird.

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

Während die anderen entweder sofort klar sind (JsonSerialiable, Array-Dereferenzierung) oder ich die Einzelheiten (Merkmale) nachgeschlagen habe, bin ich mir nicht sicher, was "Abschluss $ dieser Unterstützung" ist. Ich habe erfolglos danach gegoogelt oder auf php.net etwas darüber gefunden

Weiß jemand, was das sein soll?

Wenn ich raten müsste, würde es so etwas bedeuten:

$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;
                     }
                 };

Die Bedeutung (auch wenn dieses Beispiel trivial ist) besteht darin, dass in der Vergangenheit nach der Erstellung des Abschlusses die gebundenen 'use'-Variablen festgelegt wurden. Mit "Closure $ this Support" sind sie eher Mitglieder, mit denen Sie sich anlegen können.

Klingt dies korrekt und / oder nah und / oder vernünftig? Weiß jemand, was diese "Schließung dieser Unterstützung" bedeutet?


FWIW, 5.4 ist noch nicht der offizielle Name von PHP Trunk - es heißt intern immer noch "5.3.99" und es gibt einige Kontroversen darüber, ob es wirklich 5.4 sein wird oder nicht (vs 6.0, was dann nichts mit dem Großen zu tun hätte Unicode-Zweig "6.0" neu schreiben).
Charles

ahh gut zu wissen. Danke, dass
du das

Antworten:


74

Dies war aber schon für PHP 5.3 geplant

Für PHP 5.3 $ wurde diese Unterstützung für Closures entfernt, da kein Konsens darüber erzielt werden konnte, wie diese auf vernünftige Weise implementiert werden kann. Dieser RFC beschreibt die möglichen Wege, die zur Implementierung in der nächsten PHP-Version eingeschlagen werden können.

Dies bedeutet in der Tat, dass Sie auf die Objektinstanz verweisen können ( Live-Demo ).

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

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

Eine Diskussion finden Sie im PHP-Wiki

und für historisches Interesse:


oooh, ich bin in die völlig falsche Richtung gegangen. du meinst '$ this' ist die Instanz von Foorichtig? Ich dachte an '$ this' als die Schließung selbst. wäre usenoch nötig?
jon_darkstar

3
@ Jon Nein, die Verwendung useist nicht einmal möglich. Sie können $ this bisher in keiner PHP-Version als lexikalische Variable verwenden. Ich habe mit dem Beispiel aus dem Wiki und einem Link zu einem Codepad aktualisiert, das die Ergebnisse mit dem aktuellen PHP-Trunk zeigt.
Gordon

1
danke das ist toll Übrigens - der public $closuretut nichts und lenkt nur irgendwie von Ihrem Standpunkt ab, was Sie sonst sehr gut demonstrieren
jon_darkstar

1
@ Gordon - ich denke Jon meinte useim allgemeinen Fall - nicht spezifisch für $this. AFAIK usewird weiterhin erforderlich sein, um auf lokale Variablen zuzugreifen. Ich freue mich darauf, den use ($self)Trick fallen zu lassen. :)
David Harkness

1
@ Bracketworks Ich bin nicht 100% sicher, aber Leute, die mehr an der Entscheidung beteiligt sind, sagten mir, dass sie denken, es sei A.
Gordon

53

Eine Sache, die Gordon verpasst hat, ist das erneute Binden von $this. Während das, was er beschrieb, das Standardverhalten ist, ist es möglich, es erneut zu binden.

Beispiel

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

Die Closures- bindToInstanzmethode (alternativ die statische Methode Closure::bind) gibt einen neuen Closure mit $thiserneuter Bindung an den angegebenen Wert zurück. Der Geltungsbereich wird durch Übergeben des zweiten Arguments festgelegt. Dadurch wird die Sichtbarkeit privater und geschützter Mitglieder beim Zugriff innerhalb des Abschlusses bestimmt.


6
+1 zur Beschreibung der bindTo()Funktionalität, was ein ziemlich wichtiges Merkmal ist.
Darragh Enright

22

Aufbauend auf der Antwort von @ Gordon ist es möglich, einige hackige Aspekte der Schließung nachzuahmen - dies in 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

10
Ja, aber ein bemerkenswerter Unterschied besteht darin, dass Sie $selfinnerhalb des Abschlusses nicht auf private oder geschützte Eigenschaften oder Methoden zugreifen können .
Jgivoni

3
+1 haha, fand diese Antwort ein Jahr später und löste mein Problem. ;)
Xeoncross

@jgivoni meinst du, es ist nicht möglich auf private oder geschützte Variablen in PHP 5.3 zuzugreifen?
Shiro

2
@ Shiro, ja. Diese Problemumgehung für 5.3 funktioniert nur mit öffentlichen Eigenschaften.
Jgivoni

@Pacerier, mir ist keine Problemumgehung für den Zugriff auf nicht öffentliche Eigenschaften innerhalb von Schließungen in PHP 5.3 bekannt. Der beste Rat ist ein Upgrade auf 5.4 oder höher.
Jgivoni

2

Ich denke, dieses Beispiel zeigt, was in PHP 5.4+ möglich ist:

<?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"

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

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.