Using Anonymous Functions (Lambdas) and Closures in PHP
Having spent some significant time with more functional-oriented languages such as Scala, I have been keen to explore and take advantage of some of these concepts in my current day-to-day language (PHP). Delving into the subject however seems to highlight some confusion between the to two discussed concepts. An anonymous function (aka. lambda) originating from the Lambda calculus, is a function that has no assigned name and can be considered a value in itself. Functions of this category are first-class value types, on par with integers, booleans etc, allowing you to pass them as arguments or returned by functions (aka. higher-order functions). A closure on the other hand is a function that captures the state of the surrounding context/environment upon definition, retaining these references even if the variable falls out of lexical scope. Both do not depend on the other on an implementation level, however, you typically see the two used in conjunction. Below is an example of a trivial addition lambda and use-case.
Upon inspection of the resulting instances class type it may look incorrect. However, in PHP it can be a little confusing to disambiguate between the differences of lambdas and closures, as both create an object of the type ‘Closure’. Initially this was an implementation detail that could change in future releases, however, as time has past this fact can now be relied upon. Below is an example of using a Closure to implement increment functionality. Take notice of the inclusion of the ‘use’ keyword which allows us to disambiguate between the two concepts in code.
In the above case we create a ‘regular’ function which is supplied with the desired incremental step. When called, a new closure is returned which keeps a referential hold on the ‘$inc’ value and specified step. ‘$inc’ and ‘$step’ are local function variables that are bound/closed over the returned closure function to retain the reference.
Validation Library Example
These trivial examples are all well and good for an article example, but what may help is a concrete use-case where the power of the two concepts can be truly understood. Combined, the two provide you with the ability to allow clients to easily extend a defined implementation, supplying their own behavior, without the overhead of exploiting OO inheritance.
So as to provide a real-life use case I have abstracted out the dynamic method implementation into a trait that can then be reused. Simplify explained the following example allows a user to register a lambda/closure with the specified instance, which is invoked if no concrete method of the same name exists within the class.
The library above provides a very minimalist set of validation rules that any real-world use-case would soon demand more from. Typically, the OO hat would come on, and you would continue to extend the class definition with your own custom validaters. However, with the inclusion of the ‘DynamicMethod’ trait we are able to simply extend the functionality through use of functions. Below shows an example of creating email validation functionality by way of registering a lambda with the instance.
As you can see, we are able to access the instance variables/environment in a similar manner to methods that are defined in the class itself. We are also able to run the validation check in a similar manner too. We are then able to expand on this example by using a closure which uses the current states ‘$domains’ array to not only run the previous check but also make sure that the domain is present in a specified white-list.
Looking at the example library above I hope that you are able to notice some of the strengths that come from taking advantage of these concepts.