2012-04-12 9 views
1

ich die folgende Klasse in PHP5.3 haben:Cloning Objekt mit Verschlüssen

class MyClass { 
    public $a=1; 
    public $hook; 
    function setHook(){ 
     $t=$this; 
     $this->hook=function() use($t){ 
      echo $t->a; 
     }; 
    } 
} 

Die folgende Syntax funktioniert wie erwartet:

$x = new MyClass(); 
$x->setHook(); 
call_user_func($x->hook);  // outputs 1; 

Allerdings, wenn ich mit diesem Code weiter:

$y = clone $x; 
$y->a = 2; 
call_user_func($y->hook); 

Dann würde es immer noch 1 ausgeben. Ich verstehe WARUM es passiert, weil ich eine lokale Variable zugewiesen habe, die in die d eingebettet wurde Festlegung meines Verschlusses und anschließend in die Eigenschaft "Haken".

Bitte schlagen Sie vor, wie Sie dieses Problem umgehen können. Für eine Klasse, die eine Eigenschaft mit "callable" enthält, klone ich sie und stelle sicher, dass Verschlüsse das aktuelle Objekt korrekt referenzieren. Vielleicht kann ich einem anderen Muster folgen. Vielen Dank!

Antwort

2

Sie die $hook überschreiben könnte einfach, wenn Sie klonen:

public function __clone() { 
    $this->setHook(); 
} 

nicht sicher, ob Ihr Beispiel Vertreter Ihrer eigentlichen Code ist. Ich hoffe, es hilft.

In PHP 5.4, Sie Closure::bindTo und $this direkt im Verschluß verwenden:

class MyClass { 
    public $a = 1; 
    public $hook; 

    public function setHook(){ 
     $this->hook=function() { 
      echo $this->a; 
     }; 
    } 

    public function __clone() { 
     $this->hook = $this->hook->bindTo($this); 
    } 
} 
+0

Awesome. bindTo ist genau das, was ich brauchte, aber denkst du nicht, dass du deinen Verschluss klonen musst, bevor du wieder verbindest? Das könnte tatsächlich gut für mich funktionieren. – romaninsh

+0

Oh, eigentlich ist kein Klonen nötig: Aus doc: "Erstelle und gib eine ** neue ** anonyme Funktion zurück". Danke für eine tolle Antwort. – romaninsh

0

Ich denke, die einfachste Art und Weise self-encapsulation wäre:

private function getA() { return $this->a;} 

$this->hook=function(){ 
     echo $this->getA(); 
} 
+0

aber Sie würden – romaninsh

+0

ein wenig aktualisiert $ x-> getA() anstelle von $ y-> getA() anrufen , nicht sicher, ob es hilft, aber es könnte :) – J0HN