Eine anonyme Funktion, auch Closure genannt, ist eine Funktion ohne Namen. Du schreibst function ($param) { ... } dort, wo ein Wert erwartet wird: Weise sie einer Variable zu, übergib sie an eine andere Funktion oder gib sie zurück. Mit use ($var) kann sie Variablen aus dem umgebenden Code mitnehmen.
Jede anonyme Funktion ist ein Objekt der eingebauten Klasse Closure, und deshalb lässt sie sich speichern, weitergeben und später mit $greet(...) aufrufen.
Das Schlüsselwort use fängt als Wert ein
Eine Closure sieht äußere Variablen nicht von selbst. use ($x) kopiert den Wert von $x in die Closure, und zwar in dem Moment, in dem die Closure erzeugt wird, nicht wenn sie läuft:
use per Referenz: &$var
use (&$x) gibt der Closure die Variable selbst statt einer Kopie. Änderungen in der Closure sind draußen sichtbar, und Änderungen draußen sieht sie drinnen. So addiert ein Callback zu einer Summe oder führt einen Zähler.
Jeder Aufruf von makeCounter() erzeugt ein neues $count, und die zurückgegebene Closure hält es am Leben, nachdem die Funktion zurückgekehrt ist. Darauf bezieht sich das Wort „Closure“: Die Funktion schließt die Variablen ein, die sie braucht.
Eine Closure als Callback übergeben
Funktionen wie array_map(), array_filter(), usort() und array_walk() nehmen eine Funktion als Argument. Mit einer Closure schreibst du sie direkt an Ort und Stelle, mit so vielen Anweisungen, wie die Aufgabe braucht:
Wenn der Rumpf ein einziger Ausdruck ist, ist eine Arrow Function wie fn($p) => $p['price'] kürzer und braucht kein use.
Callables: Funktionsnamen, Methoden und strlen(...)
Ein Parameter vom Typ callable akzeptiert mehr als Closures. Ein String mit einem Funktionsnamen, ein Array mit einem Objekt und einem Methodennamen und ein Array mit einem Klassennamen und einem statischen Methodennamen zählen alle dazu. Seit PHP 8.1 macht die First-Class-Callable-Syntax strlen(...) aus jedem davon direkt eine Closure.
Die Form (...) wird beim Ausführen der Zeile geprüft: Ein Tippfehler wirft genau dort einen Error. Ein String wie 'strtoupr' ist nur ein String, bis jemand versucht, ihn aufzurufen.
Closures in einer Klasse: $this und static
Eine Closure, die in einer Methode erzeugt wird, hat $this automatisch gebunden und kann die Eigenschaften des Objekts verwenden. Markiere sie als static function, wenn sie $this nicht braucht; das verhindert auch, dass sie das Objekt am Leben hält.
use vergessen
Der häufigste Closure-Bug ist, eine äußere Variable zu verwenden, ohne sie in use aufzuführen. In der Closure existiert die Variable nicht:
$minAge = 18;
$adults = array_filter($people, function ($p) {
return $p['age'] >= $minAge; // $minAge is not in use (...)
});
PHP prints: Warning: Undefined variable $minAge
$minAge ist drinnen null, jedes Alter, das mit >= null verglichen wird, ist true, und jede Person besteht den Filter. Auf einem Server, der Warnungen versteckt, sagt dir nichts Bescheid. Füge die Variable zu use hinzu:
Häufig gestellte Fragen
Was ist eine Closure in PHP?
Eine Funktion ohne Namen, erzeugt mit function (...) { ... } und in einer Variable gespeichert oder als Argument übergeben. PHP stellt sie als Objekt der Klasse Closure dar. Sie kann Variablen aus dem Scope mitnehmen, in dem sie erzeugt wurde, aufgeführt in use (...).
Was macht das Schlüsselwort use in einer PHP-Closure?
use ($x) kopiert die äußere Variable $x in die Closure, wenn die Closure erzeugt wird. Spätere Änderungen an $x draußen sieht sie nicht. Schreib use (&$x), um die Variable stattdessen zu teilen, sodass Änderungen in beide Richtungen wirken.
Was ist ein Callable in PHP?
Alles, was PHP aufrufen kann: eine Closure, ein Funktionsname als String ('strtoupper'), ein Array [$object, 'method'] oder [ClassName::class, 'staticMethod'] oder ein Objekt mit __invoke(). Verwende den Typ callable, um all das anzunehmen, und is_callable(), um es zu prüfen.
Was bedeutet strlen(...) in PHP?
Das ist die First-Class-Callable-Syntax aus PHP 8.1: strlen(...) erzeugt eine Closure aus der Funktion, ohne sie aufzurufen. Sie funktioniert auch für Methoden, $obj->method(...), und statische Methoden, Foo::bar(...), und wird beim Ausführen der Zeile geprüft, anders als ein Name als String.
Brauche ich nach einer anonymen Funktion ein Semikolon?
Ja, wenn du sie zuweist: $f = function () { ... }; ist eine Zuweisung und endet deshalb mit ;. Fehlt es, ist das ein Parse-Fehler. Eine Closure, die direkt als Argument übergeben wird, braucht kein eigenes Semikolon.