Closure != Lambda

Tags:

Seit PHP 5.3 kommen auch wir PHP-Programmier in den Genuss von Lambdas und Closures. Obwohl die beiden Features zur selben Zeit implementiert wurden und sich auch nahe stehen (können), handelt es sich dabei aber um zwei unterschiedliche Konzepte. Ein Versuch der Aufklärung.

Lambdas

Lambdas sind anonyme Funktionen. Sie haben also keinen Bezeichner/Namen, sondern werden in Variablen gespeichert, an Funktionen übergeben oder von Funktionen zurückgegeben. In einigen Programmiersprachen gibt es ein spezielles Schlüsselwort (meist eben dieses lambda) um anonyme Funktionen zu definieren. In PHP nutzt man das alt-bekannte function.

// Anonyme Funktion
$gruss = function() {
    echo 'Hallo';
}

$gruss(); // Hallo

// Benannte Funktion die eine anonyme Funktion
// als erstes Argument entgegennimmt und eine
// anonyme Funktion zurückgibt.
function namedFunction(\Closure $anonFunc) {
    $anonFunc();
    return function() {
        echo 'Welt';
    };
}

$gegruesseter = namedFunction($gruss); // Hallo
$gegruesseter();                       // Welt

Was beim letzten Beispiel auf die falsche Fährte lockt ist der \Closure Typ-Hint. Der kommt daher, dass PHP sowohl anonyme Funktionen als auch Closures mit einem Compiler-Trick implementiert und jeweils als Objekt der Klasse \Closure abbildet. Was wir oben benutzt haben sind aber nur anonyme Funktionen, keine Closures. Zu denen kommen wir jetzt.

Closures

Bei Closures geht es um Variablen und den Gültigkeitsbereich (scope), in welchem eine Funktion definiert wurde. Und mit "Funktion" meine ich eben nicht nur anonyme, sondern auch benannte Funktionen. Das Problem ist, dass die meisten Programmiersprachen Closures für benannte Funktionen nicht unterstützen. Deshalb werden Closures oft mit anonymen Funktionen/Lambdas gleichgesetzt.

Normalerweise sind Variablen innerhalb einer Funktion nach dem Verlassen derer nicht mehr verfügbar.

function func() {
    $i = 0;
}
isset($i); // <- false

Mit Hilfe von Closures kann man diese Variablen aber am Leben erhalten, in dem man sie in einem anderen Gültigkeitsbereich (= eine andere Funktion) kapselt.

function func() {
    $i = 5;
    return function() use ($i) {
        echo $i;
    };
}

$x = func();
$x(); // 5

Möchte man $i innerhalb des Closures editierbar machen, muss man die Variable referenzieren.

function func() {
    $i = 0;
    return array(
        function() use (&$i) {
            echo $i;
        },
        function($j = 1) use (&$i) {
            $i += $j;
        },
    );
}

list($prnt, $incr) = func();
$prnt(); // 0
$incr();
$incr();
$prnt(); // 2
$incr(4);
$prnt(); // 6

Closures kommen aus der funktionalen Programmierung und dort ist es eigentlich nicht üblich, dass Variablen editiert werden können. Deshalb implementiert jede Sprache diesen Spezialfall auch ein bisschen anders.

Zum Abschluss noch ein Beispiel in Python. Dieses kennt nämlich lokale Funktionen und ab Version 3 auch das Schlüsselwort nonlocal, um Variablen des umgebenden Gültigkeitbereiches zu referenzieren.

def func():
    x = 0
    def printX():
        nonlocal x
        print x
    def incrementX(j = 1):
        nonlocal x
        x += j
    return printX, incrementX

prnt, incr = func()
prnt() # 0
incr()
incr()
prnt() # 2
incr(4)
prnt() # 6

Die Funktionen printX und incrementX sind keine anonymen Funktionen, sondern lokal definierte Funktionen der func Funktion. In PHP geht das so nicht.

Ähnliche Artikel

Kommentare