5.5.5 Anonyme Funktionen und Closure

Wir gehen hier einen Schritt zurück und schauen uns Funktionen (also keine Methoden, sondern normale Funktionen) an. Hierbei kommen wir aber gleich zu einer Besonderheit, den anonymen Funktionen.

Anonyme Funktionen sind interessant, da man nun eine Funktion in einer Variablen speichern kann. Und die Variable kann beispielsweise wiederum in einem Array gespeichert werden. Damit hätten wir Funktionen, die über den Umweg einer Variablen in einem Array speicherbar sind. So etwas konnten wir bisher nicht machen.

Die Funktion function add($x, $y) in Zeile 3 ist eine normale Funktion, die in Zeile 10 normal aufgerufen wird.

Die Funktion function($x, $y) in Zeile 13 ist eine anonyme Funktion, da der Name der Funktion fehlt. Aber dafür wird die Funktion einer Variablen zugewiesen: $multiply = function($x, $y). Auch der Aufruf der Funktion in Zeile 20 ist anders als gewohnt.

<?php
// normale Funktion
function add($x, $y)
{
    $z = $x + $y;
    echo "Die Addition hat als Ergebnis: $z <br>";
}

// Aufruf der normalen Funktion
add(3, 4);

// anonyme Funktion definieren in dem man eine Variable zuweist
$multiply = function($x, $y)
{
    $z = $x * $y;
    echo "Die Multiplikation hat als Ergebnis: $z <br>";
};  // Semikolon ist hier notwendig

// Aufruf der anonymen Funktion
$multiply(3, 4);

// Aber was ist eigentlich $multiply für eine "seltsame Variable"
print_r($multiply);

Ausgabe:
Die Addition hat als Ergebnis: 7
Die Multiplikation hat als Ergebnis: 12
Closure Object ( [parameter] => Array ( [\(x] => [\)y] => ) )

In der Ausgabe ergeben die ersten beiden Zeilen das gewünschte Resultat. Aber die Ausgabe mit print_r($multiply); (Zeile 23) ist "seltsam".

Intern erzeugt PHP für eine anonyme Funktion eine Klasse Closure. Und $multiply enthält nun ein Objekt der Klasse. Diesem Objekt werden die Variablen $x und $y übergeben.

Hinweis für PHP Experten

PHP-intern ist die Closure als Klasse implementiert und nutzt die magische Methode __invoke().

Die __invoke()-Methode wird aufgerufen, wenn ein Skript versucht, ein Objekt als Funktion aufzurufen.

Wichtig

Sie haben hier also drei Dinge gelernt:

  • Man kann anonyme Funktionen erstellen, indem man die Funktion einer Variablen zuweist, also $variable = function (...) zugewiesen werden.
  • Intern arbeitet PHP oft objektorientiert, ohne das wir dies merken.
  • Sie haben die Begriffe "anonyme Funktion" und "Closure" kennen gelernt.

Objektorientiertes Beispiel einer anonymen Funktion

Wenn Sie das Vorherige verstanden haben, dann kommt hier etwas Ungewohntes zum Knobeln. Aber damit es nicht ganz so schwierig wird, ist der nachfolgende Sourcecode entsprechend kommentiert. Also bitte versuchen Sie den Sourcecode anhand der Kommentare zu verstehen.

<?php

// Klasse Value bekommt im Konstruktor eine Variable $value
// und speichert diese als Eigenschaft
class Value {
    protected $value;

    public function __construct(int $value) 
    {
        $this->value = $value;
    }

    public function getValue(): int 
    {
        return $this->value;
    }
}

// Hauptprogramm
// Objekte der Klasse Value erzeugen
$three = new Value(3);
$four = new Value(4);

// Anonyme Funktion erzeugt automatisch ein Objekt der vordefinierten Klasse Closure
// und instanziert automatisch ein Objekt (hier: $add)
$add = function($delta)
{
    // Die anonyme Funktion hat über call() - siehe Zeile 39 bzw. 40
    // das Objekt $three bzw. $four übergeben bekommen 
    // und es kann $this->getValue() aufgerufen werden.

    $sum = $this->getValue() + $delta;
    echo $sum . "<br>";
};

// call() ist eine Methode der Klasse Closure
// und übergibt ein Objekt (hier $three bzw. $four)
// und damit wird die anonyme Funktion aufgerufen.
$add->call($three, 10);
$add->call($four, 10);

Ausgabe:
13
14

Hinweis

Auf den ersten Blick unverständlichen Sourcecode sollten Sie immer in Ihren Editor kopieren (z.B. PHPStorm) und dort analysieren. Dann ist das Verständnis des Sourcecodes wirklich leichter.