Używanie `$ this` w anonimowej funkcji w PHP w wersji wcześniejszej niż 5.4.0

86

Podręcznik PHP stwierdza

Nie można używać $thisfunkcji anonimowej przed PHP 5.4.0

na stronie funkcji anonimowych . Ale odkryłem, że mogę sprawić, by działało, przypisując $thisdo zmiennej i przekazując zmienną do useinstrukcji w definicji funkcji.

$CI = $this;
$callback = function () use ($CI) {
    $CI->public_method();
};

Czy to dobra praktyka?
Czy istnieje lepszy sposób na dostęp $thisdo anonimowej funkcji przy użyciu PHP 5.3?

steampowered
źródło
1
Tylko niewielka konwencja na forum - zwykle lepiej jest przyjąć odpowiedź niż edytować pytanie, aby odzwierciedlić preferowaną odpowiedź. Głównie dzieje się tak, aby odpowiedzi nadal miały sens w sposób ciągły, ale także oczywiście po to, aby dać kredyt za poprawną odpowiedź.
halfer
4
Uważaj $CI = $this;i $CI =& $this; nie są identyczne. Może do twoich celów, ale to nie to samo. Wypróbuj $CI = 'bla'; var_dump($this);obie wersje, aby zobaczyć różnicę.
Rudie
1
@Rudie Dodaję dokumentację do twojego komentarza
steampowered
@steampowered Jest gdzieś w Internecie dobry przykład / artykuł na ten temat, ale nie mogłem go znaleźć =) Przepraszamy. Po prostu spróbuj, jeśli nie widzisz różnicy. To oczywiste.
Rudie,

Odpowiedzi:

67

Nie powiedzie się, gdy spróbujesz wywołać chronioną lub prywatną metodę, ponieważ użycie jej w ten sposób liczy się jako wywołanie z zewnątrz. O ile wiem, nie ma sposobu na obejście tego w 5.3, ale w PHP 5.4 będzie działać zgodnie z oczekiwaniami, po wyjęciu z pudełka:

class Hello {

    private $message = "Hello world\n";

    public function createClosure() {
        return function() {
            echo $this->message;
        };
    }

}
$hello = new Hello();
$helloPrinter = $hello->createClosure();
$helloPrinter(); // outputs "Hello world"

Co więcej, będziesz mógł zmienić to, na co wskazuje $ this w czasie wykonywania, dla funkcji anonimowych (ponowne wiązanie zamknięcia):

class Hello {

    private $message = "Hello world\n";

    public function createClosure() {
        return function() {
            echo $this->message;
        };
    }

}

class Bye {

    private $message = "Bye world\n";

}

$hello = new Hello();
$helloPrinter = $hello->createClosure();

$bye = new Bye();
$byePrinter = $helloPrinter->bindTo($bye, $bye);
$byePrinter(); // outputs "Bye world"

W efekcie funkcje anonimowe będą miały metodę bindTo () , w której pierwszy parametr może być użyty do określenia, na co wskazuje $ this, a drugi parametr kontroluje, jaki powinien być poziom widoczności . Jeśli pominiesz drugi parametr, widoczność będzie podobna do wywoływania z „zewnątrz”, np. możliwy jest dostęp tylko do właściwości publicznych. Zwróć również uwagę na sposób działania bindTo, nie modyfikuje oryginalnej funkcji, zwraca nową .

K. Norbert
źródło
1
Oznaczanie odpowiedzi jako poprawnej, ale tylko w celu wyjaśnienia dla innych czytelników: konwencja zastosowana w pytaniu będzie działać w przypadku metod publicznych wykorzystujących obiekt, do którego się odwołuje $this.
steampowered
5
Dostęp do metod niepublicznych można uzyskać za pomocą refleksji. Nieefektywne i trochę złe, ale działa.
outis
7

Nie zawsze polegaj na PHP, aby przekazywać obiekty przez referencje, kiedy sam przypisujesz referencję, zachowanie nie jest takie samo, jak w większości języków OO, w których oryginalny wskaźnik jest modyfikowany.

twój przykład:

$CI = $this;
$callback = function () use ($CI) {
$CI->public_method();
};

Powinien być:

$CI = $this;
$callback = function () use (&$CI) {
$CI->public_method();
};

UWAGA ODNIESIENIA "&" i $ CI powinny być przypisane po wykonaniu ostatecznych wywołań, w przeciwnym razie możesz otrzymać nieprzewidywalne wyniki, w PHP dostęp do referencji nie zawsze jest taki sam jak dostęp do oryginalnej klasy - jeśli to ma sens.

http://php.net/manual/en/language.references.pass.php

Christof Coetzee
źródło
6

To jest normalny sposób.
btw, spróbuj usunąć &to powinno działać bez tego, ponieważ obiekty w jakikolwiek sposób przechodzą obok ref.

Itay Moav -Malimovka
źródło
1

Wydaje się to w porządku, jeśli przekazanie przez odniesienie jest właściwym sposobem na zrobienie tego. Jeśli używasz PHP 5, nie potrzebujesz &wcześniej symbolu, $thisponieważ zawsze będzie on przekazywany przez odniesienie, niezależnie od tego.

ogień
źródło
2
OP musi korzystać z wersji 5.3 lub nowszej, ponieważ 4.x nie obsługiwał funkcji anonimowych :-)
halfer
1

Jest okej. Myślę, że możesz to również zrobić:

$CI = $this;

... ponieważ przypisania obejmujące obiekty zawsze będą kopiować odniesienia, a nie całe obiekty.

halfer
źródło