Hallo zusammen, Heute möchte ich eine Kleinigkeit über die sogenannten „Lambda“ (Oder auch „Anonyme“) Funktionen schreiben, bevor ich nächste Woche die aktuelle Serie („Das eigene kleine Portfolio mit dem Slim Framework, RainTPL & Co.“) abschließe.

Was sind Lambda Funktionen?

Lambda Funktionen unterscheiden sich eigentlich nur in folgenden Punkten gegenüber normalen Funktionen:

  • Sie lassen sich in Variablen speichern…
  • …und dadurch als Parameter an Funktionen und Methoden übergeben

Den PHP Entwicklern wurde dieses Feature zwar schon in 4.0.1 ermöglicht (dazu später mehr) doch erst in Version 5.3 wirklich brauchbar umgesetzt.

Ich habe übrigens schon öfters Lambda-Funktionen in Code-Beispielen benutzt – Zuletzt im letzten Posting. Das Slim Framework benutzt Lambda-Funktionen als Callback für sein Routing!

Lambda Funktionen sehen in PHP folgendermaßen aus:

$hello = function ($parameter) {
    return "Hello " . $parameter . "!";
};

$hallowelt = $hello('world'); // "Hello world!"

// Lambda Funktionen lassen sich direkt als Parameter übergeben:
$test = meine_funktion(function() {
    return 'Test';
});

Erinnert an Javascript, oder?

Was fällt auf?

Zu aller erst: Lambda-Funktionen haben keine Namen. Sie werden direkt aus der Variable heraus angesprochen – Ähnlich wie Klasseninstanzen. Tatsächlich sind Lambda-Funktionen im Hintergrund reine Instanzen der Closure Klasse.

Eine Funktion als Parameter?

Wie oben kurz erwähnt nutzt z.B. das Slim Framework und auch Kohana die Anonymen Funktionen zum Routing. Auch RainTPL unterstützt Lambda-Funktionen im Bereich des „eigene Tags definieren“ Features (Siehe Posting „Das eigene kleine Portfolio mit dem Slim Framework, RainTPL & Co. – Teil 2„).

Wie reagiere ich auf eine Lambda-Funktion?

Wenn wir eigene Funktionen oder Methoden entwickeln in denen wir Lambda-Funktionen erlauben, sollten wir wissen wie wir auf diese reagieren können – bzw. wie wir prüfen können ob es sich bei dem Parameter tatsächlich um eine Anonyme Funktion handelt – Hier machen wir uns die Tatsache zunutze, das Lambda-Funktionen in PHP reine Instanzen der Closure Klasse sind:

// Syntax zum prüfen auf eine Lambda-Funktion
function meine_funktion($func)
{
    if ($func instanceof Closure)
    {
        // Es handelt sich um eine Lambda-Funktion.
    }
}

// Oder...
function meine_funktion(Closure $func)
{
    // ...
}

Alternativ könnten wir die Funktion is_callable nutzen, doch diese wird uns auch bei diversen anderen Fällen true zurückliefern:

// Test für Lambda-Funktionen
function teste_lambda($func)
{
    var_dump(is_callable($func));
    var_dump($func instanceof Closure);
}

// Eine echte Lambda-Funktion:
teste_lambda(function(){}); // true, true

// Der Name einer existierenden Funktion
teste_lambda('teste_lambda'); // true, false

// Eine existierende Methode einer Klasse
teste_lambda(array('klasse', 'methode')); // true, false

Anonyme Funktionen in PHP 4?

Ja, richtig gelesen. Lambda-Funktionen gab es auch schon in PHP4 (Ab 4.0.1) – Allerdings waren die Möglichkeiten etwas beschränkt und die Syntax eher umständlich:

// Anonyme Funktionen in PHP 4.0.1
$hello = create_function('$parameter', 'return "Hello " . $parameter . "!";');
echo $hello('world'); // "Hello world!"

Möchte man mehrere Parameter nutzen, müssen diese mit Komma separiert werden. Der „Quelltext“ sollte idealerweise innerhalb einfacher Hochkommas geschrieben werden – Werden doppelte benutzt, müssen die Variablen escaped werden:

$hello = create_function("\$parameter", "return 'Hello ' . \$parameter . '!';");

Rekursive Lambda-Funktion?

Früher oder später stoßen wir ggf. auf den Fall das wir eine Methode oder Funktion rekursiv aufrufen möchten… Bei normalen Funktionen und Methoden ist das kein Problem – Bei den Anonymen hingegen kann es etwas schwieriger ausfallen, da diese keinen Namen haben: Damit die Funktion also im eigenen Kontext erreichbar ist, binden wir diese als Referenz via closure einfach dran.

// Rekursive Lambda-Funktion für verkettete Exceptions.
$print_exception = function ($exception) use (&$print_exception) {
    echo $exception->getMessage() . ' [' . $exception->getFile() . ':' . $exception->getLine() . ']';

    if (($previous_exception = $exception->getPrevious()) !== null) 
    {
        $print_exception($previous_exception);
    }
};

// Irgendwo weiter im Quelltext...
try 
{
    // ...
} 
catch (Exception $e)
{
    $print_exception($e);
}

Und mit diesen Worten möchte ich mich auch schon für Heute von euch verabschieden. Nächste Woche gibt es dann Teil 5 der Serie „Das eigene kleine Portfolio mit dem Slim Framework, RainTPL & Co.“.
Ich würde mich freuen wenn ihr auch dann wieder reinschaut 😉 !

Euch da draußen wünsche ich eine angenehme Woche!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.