Anonyme Funktionen
Anonyme Funktionen, auch bekannt als Closures
, ermöglichen es Funktionen
ohne Funktionsnamen zu schreiben. Sie sind am wertvollsten als Werte von callable-Parametern,
haben aber noch viele andere Verwendungsmöglichkeiten.
Anonyme Funktionen werden unter Verwendung der
Closure-Klasse implementiert.
Beispiel #1 Beispiel für eine anonyme Funktion
<?php
echo preg_replace_callback('~-([a-z])~', function ($match) {
return strtoupper($match[1]);
}, 'hallo-welt');
// gibt halloWelt aus
?>
Closures können auch als Werte von Variablen verwendet werden;
PHP konvertiert solche Ausdrücke automatisch in Instanzen der internen Klasse Closure.
Die Zuweisung einer Closure an eine Variable verwendet die selbe Syntax wie andere
Zuweisungen, einschließlich des abschließenden Semikolon:
Beispiel #2 Beispiel für die Zuweisung einer anonymen Funktion
<?php
$greet = function($name)
{
printf("Hallo %s\r\n", $name);
};
$greet('Welt');
$greet('PHP');
?>
Closures können ebenfalls Variablen aus dem Eltern-Gültigkeitsbereich erben.
Jede solche Variable muss an das use
-Sprachkonstrukt übergeben werden.
Von PHP 7.1 an dürfen diese Variablen keine superglobals,
$this oder Variablen mit dem gleichen Name wie ein
Parameter sein.
Beispiel #3 Erben von Variablen aus dem Eltern-Scope
<?php
$message = 'hallo';
// Kein "use"
$example = function () {
var_dump($message);
};
$example();
// $message vererben
$example = function () use ($message) {
var_dump($message);
};
$example();
// der Wert einer geerbten Variable ist der zum Zeitpunkt
// der Funktionsdefinition, nicht des Funktionsaufrufs
$message = 'welt';
$example();
// $message wieder herstellen
$message = 'hallo';
// vererben per Referenz
$example = function () use (&$message) {
var_dump($message);
};
$example();
// Der geänderte Wert im Eltern-Gültigkeitsbereich
// wird in der aufgerufenen Funktion reflektiert
$message = 'welt';
$example();
// Closures können ebenfalls reguläre Parameter akzeptieren
$example = function ($arg) use ($message) {
var_dump($arg . ' ' . $message);
};
$example("hallo");
?>
Das oben gezeigte Beispiel erzeugt eine ähnliche Ausgabe wie:
Notice: Undefined variable: message in /example.php on line 6
NULL
string(5) "hallo"
string(5) "hallo"
string(5) "hallo"
string(4) "welt"
string(10) "hallo welt"
As of PHP 8.0.0, the list of scope-inherited variables may include a trailing
comma, which will be ignored.
Das Erben von Variablen aus dem Eltern-Gültigkeitsbereich ist nicht
das gleiche wie die Verwendung von globalen Variablen.
Globale Variablen existieren im globalen Gültigkeitsbereich, der immer der gleiche ist,
unabhängig davon welche Funktion ausgeführt wird. Der Eltern-Gültigkeitsbereich einer
Closure ist die Funktion, in der die Closure deklariert wurde (nicht notwendigerweise
die Funktion, aus der sie aufgerufen wurde). Betrachten Sie das folgende Beispiel:
Beispiel #4 Closures und Gültigkeitsbereiche
<?php
// Ein einfacher Einkaufswagen, der eine Liste von hinzugefügten Produkten
// enthält, und die Menge jedes Produkts. Enthält eine Methode, die den
// Gesamtpreise der Waren im Einkaufswagen unter Verwendung einer Closure
// als Callback berechnet.
class Cart
{
const PRICE_BUTTER = 1.00;
const PRICE_MILK = 3.00;
const PRICE_EGGS = 6.95;
protected $products = array();
public function add($product, $quantity)
{
$this->products[$product] = $quantity;
}
public function getQuantity($product)
{
return isset($this->products[$product]) ? $this->products[$product] :
FALSE;
}
public function getTotal($tax)
{
$total = 0.00;
$callback =
function ($quantity, $product) use ($tax, &$total)
{
$pricePerItem = constant(__CLASS__ . "::PRICE_" .
strtoupper($product));
$total += ($pricePerItem * $quantity) * ($tax + 1.0);
};
array_walk($this->products, $callback);
return round($total, 2);
}
}
$my_cart = new Cart;
// Lege ein paar Waren in den Einkaufskorb
$my_cart->add('butter', 1);
$my_cart->add('milk', 3);
$my_cart->add('eggs', 6);
// Gib die Gesamtsumme mit einer Mehrwertsteuer von 5% aus
print $my_cart->getTotal(0.05) . "\n";
// Das Ergebnis ist 54.29
?>
Beispiel #5 Automatisches Binden von $this
<?php
class Test
{
public function testing()
{
return function() {
var_dump($this);
};
}
}
$object = new Test;
$function = $object->testing();
$function();
?>
Wird eine anonyme Funktion im Kontext einer Klasse deklariert, so wird diese
Klasse automatisch an jene gebunden, was $this
innerhalb des
Geltungsbereichs verfügbar macht. Ist diese automatische Bindung der aktuellen
Klasse nicht erwünscht, dann können stattdessen statische anonyme Funktionen
verwendet werden.
Statische anonyme Funktionen
Anonyme Funktionen können statisch deklariert werden. Dies verhindert,
dass automatisch die aktuelle Klasse an sie gebunden wird. Objekte können zur Laufzeit
ebenfalls nicht an sie gebunden werden.
Beispiel #6 Versuch der Verwendung von $this
innerhalb einer statischen anonymen Funktion
<?php
class Foo
{
function __construct()
{
$func = static function() {
var_dump($this);
};
$func();
}
};
new Foo();
?>
Das oben gezeigte Beispiel erzeugt folgende Ausgabe:
Notice: Undefined variable: this in %s on line %d
NULL
Beispiel #7 Versuch ein Objekt an eine statische anonyme Funktion zu binden
<?php
$func = static function() {
// function body
};
$func = $func->bindTo(new StdClass);
$func();
?>
Das oben gezeigte Beispiel erzeugt folgende Ausgabe:
Warning: Cannot bind an instance to a static closure in %s on line %d