Anonymous recursive PHP functions
I know this might not be a simple approach, but I learned about a technique called «fix» from functional languages. The fix function from Haskell is known more generally as the Y combinator, which is one of the most well-known fixed point combinators.
A fixed point is a value that is unchanged by a function: a fixed point of a function f is any x such that x = f(x). A fixed point combinator y is a function that returns a fixed point for any function f. Since y(f) is a fixed point of f, we have y(f) = f(y(f)).
Essentially, the Y combinator creates a new function that takes all the arguments of the original, plus an additional argument that’s the recursive function. How this works is more obvious using curried notation. Instead of writing arguments in parentheses ( f(x,y. ) ), write them after the function: f x y . . The Y combinator is defined as Y f = f (Y f) ; or, with a single argument for the recursed function, Y f x = f (Y f) x .
Since PHP doesn’t automatically curry functions, it’s a bit of a hack to make fix work, but I think it’s interesting.
function fix( $func ) < return function() use ( $func ) < $args = func_get_args(); array_unshift( $args, fix($func) ); return call_user_func_array( $func, $args ); >; > $factorial = function( $func, $n ) < if ( $n == 1 ) return 1; return $func( $n - 1 ) * $n; >; $factorial = fix( $factorial ); print $factorial( 5 );
Note this is almost the same as the simple closure solutions others have posted, but the function fix creates the closure for you. Fixed point combinators are slightly more complex than using a closure, but are more general, and have other uses. While the closure method is more suitable for PHP (which isn’t a terribly functional language), the original problem is more of an exercise than for production, so the Y combinator is a viable approach.
Solution 3
Although it is not for practial usage, The C-level extension mpyw-junks/phpext-callee provides anonymous recursion without assigning variables.
)(5)); // 5! = 5 * 4 * 3 * 2 * 1 = int(120)
Recursive anonymous function php
Watch out when ‘importing’ variables to a closure’s scope — it’s easy to miss / forget that they are actually being *copied* into the closure’s scope, rather than just being made available.
So you will need to explicitly pass them in by reference if your closure cares about their contents over time:
$one (); // outputs NULL: $result is not in scope
$two (); // outputs int(0): $result was copied
$three (); // outputs int(1)
?>
Another less trivial example with objects (what I actually tripped up on):
//set up variable in advance
$myInstance = null ;
$broken = function() uses ( $myInstance )
if(!empty( $myInstance )) $myInstance -> doSomething ();
>;
//$myInstance might be instantiated, might not be
if( SomeBusinessLogic :: worked () == true )
$myInstance = new myClass ();
>
$broken (); // will never do anything: $myInstance will ALWAYS be null inside this closure.
$working (); // will call doSomething if $myInstance is instantiated
/*
(string) $name Name of the function that you will add to class.
Usage : $Foo->add(function()<>,$name);
This will add a public function in Foo Class.
*/
class Foo
public function add ( $func , $name )
$this -> < $name >= $func ;
>
public function __call ( $func , $arguments ) call_user_func_array ( $this ->< $func >, $arguments );
>
>
$Foo = new Foo ();
$Foo -> add (function() echo «Hello World» ;
>, «helloWorldFunction» );
$Foo -> add (function( $parameterone ) echo $parameterone ;
>, «exampleFunction» );
$Foo -> helloWorldFunction (); /*Output : Hello World*/
$Foo -> exampleFunction ( «Hello PHP» ); /*Output : Hello PHP*/
?>?php
In case you were wondering (cause i was), anonymous functions can return references just like named functions can. Simply use the & the same way you would for a named function. right after the `function` keyword (and right before the nonexistent name).
$x =& $fn ();
var_dump ( $x , $value ); // ‘int(0)’, ‘int(0)’
++ $x ;
var_dump ( $x , $value ); // ‘int(1)’, ‘int(1)’
Every instance of a lambda has own instance of static variables. This provides for great event handlers, accumulators, etc., etc.
Creating new lambda with function() < . >; expression creates new instance of its static variables. Assigning a lambda to a variable does not create a new instance. A lambda is object of class Closure, and assigning lambdas to variables has the same semantics as assigning object instance to variables.
Example script: $a and $b have separate instances of static variables, thus produce different output. However $b and $c share their instance of static variables — because $c is refers to the same object of class Closure as $b — thus produce the same output.
function generate_lambda () : Closure
# creates new instance of lambda
return function( $v = null ) static $stored ;
if ( $v !== null )
$stored = $v ;
return $stored ;
>;
>
$a = generate_lambda (); # creates new instance of statics
$b = generate_lambda (); # creates new instance of statics
$c = $b ; # uses the same instance of statics as $b
$a ( ‘test AAA’ );
$b ( ‘test BBB’ );
$c ( ‘test CCC’ ); # this overwrites content held by $b, because it refers to the same object
var_dump ([ $a (), $b (), $c () ]);
?>
This test script outputs:
array(3) [0]=>
string(8) «test AAA»
[1]=>
string(8) «test CCC»
[2]=>
string(8) «test CCC»
>
/*
* An example showing how to use closures to implement a Python-like decorator
* pattern.
*
* My goal was that you should be able to decorate a function with any
* other function, then call the decorated function directly:
*
* Define function: $foo = function($a, $b, $c, . ) <. >
* Define decorator: $decorator = function($func) <. >
* Decorate it: $foo = $decorator($foo)
* Call it: $foo($a, $b, $c, . )
*
* This example show an authentication decorator for a service, using a simple
* mock session and mock service.
*/
/*
* Define an example decorator. A decorator function should take the form:
* $decorator = function($func) * return function() use $func) * // Do something, then call the decorated function when needed:
* $args = func_get_args($func);
* call_user_func_array($func, $args);
* // Do something else.
* >;
* >;
*/
$authorise = function( $func ) return function() use ( $func ) if ( $_SESSION [ ‘is_authorised’ ] == true ) $args = func_get_args ( $func );
call_user_func_array ( $func , $args );
>
else echo «Access Denied» ;
>
>;
>;
/*
* Define a function to be decorated, in this example a mock service that
* need to be authorised.
*/
$service = function( $foo ) echo «Service returns: $foo » ;
>;
/*
* Decorate it. Ensure you replace the origin function reference with the
* decorated function; ie just $authorise($service) won’t work, so do
* $service = $authorise($service)
*/
$service = $authorise ( $service );
/*
* Establish mock authorisation, call the service; should get
* ‘Service returns: test 1’.
*/
$_SESSION [ ‘is_authorised’ ] = true ;
$service ( ‘test 1’ );
/*
* Remove mock authorisation, call the service; should get ‘Access Denied’.
*/
$_SESSION [ ‘is_authorised’ ] = false ;
$service ( ‘test 2’ );
Beware of using $this in anonymous functions assigned to a static variable.
class Foo public function bar () static $anonymous = null ;
if ( $anonymous === null ) // Expression is not allowed as static initializer workaround
$anonymous = function () return $this ;
>;
>
return $anonymous ();
>
>
$a = new Foo ();
$b = new Foo ();
var_dump ( $a -> bar () === $a ); // True
var_dump ( $b -> bar () === $a ); // Also true
?>
In a static anonymous function, $this will be the value of whatever object instance that method was called on first.
To get the behaviour you’re probably expecting, you need to pass the $this context into the function.
class Foo public function bar () static $anonymous = null ;
if ( $anonymous === null ) // Expression is not allowed as static initializer workaround
$anonymous = function ( self $thisObj ) return $thisObj ;
>;
>
return $anonymous ( $this );
>
>
$a = new Foo ();
$b = new Foo ();
var_dump ( $a -> bar () === $a ); // True
var_dump ( $b -> bar () === $a ); // False
?>
You can always call protected members using the __call() method — similar to how you hack around this in Ruby using send.
class Fun
<
protected function debug ( $message )
<
echo «DEBUG: $message \n» ;
>
public function yield_something ( $callback )
<
return $callback ( «Soemthing!!» );
>
public function having_fun ()
<
$self =& $this ;
return $this -> yield_something (function( $data ) use (& $self )
<
$self -> debug ( «Doing stuff to the data» );
// do something with $data
$self -> debug ( «Finished doing stuff with the data.» );
>);
>
// Ah-Ha!
public function __call ( $method , $args = array())
<
if( is_callable (array( $this , $method )))
return call_user_func_array (array( $this , $method ), $args );
>
>
$fun = new Fun ();
echo $fun -> having_fun ();
When using anonymous functions as properties in Classes, note that there are three name scopes: one for constants, one for properties and one for methods. That means, you can use the same name for a constant, for a property and for a method at a time.
Since a property can be also an anonymous function as of PHP 5.3.0, an oddity arises when they share the same name, not meaning that there would be any conflict.
Consider the following example:
class MyClass const member = 1 ;
public function member () return «method ‘member'» ;
>
public function __construct () $this -> member = function () return «anonymous function ‘member'» ;
>;
>
>
header ( «Content-Type: text/plain» );
var_dump ( MyClass :: member ); // int(1)
var_dump ( $myObj -> member ); // object(Closure)#2 (0) <>
var_dump ( $myObj -> member ()); // string(15) «method ‘member'»
$myMember = $myObj -> member ;
var_dump ( $myMember ()); // string(27) «anonymous function ‘member'»
?>
That means, regular method invocations work like expected and like before. The anonymous function instead, must be retrieved into a variable first (just like a property) and can only then be invoked.
Recursive anonymous functions in PHP
Now that anonymous functions have been available since PHP 5.3, I find myself making use of them quite often. However, the one thing that I couldn’t seem to get right was being able to make an anonymous function reference itself — in so doing, calling itself recursively.
How do you do this? Like so:
$func = function ($level = 0) echo str_repeat(' ', $level) . "I am on level $level>\n"; >; $func(); $func(1); $func(2); $func(3);
This becomes tedious to call over & over (it could be placed in a for loop to accomplish the same thing — but this is just a simplistic example). So, how do we implement this as an anonymous function that calls itself recursively? There are two things that need to take place for this to happen:
- Ensure that the recursive of the anonymous function is limited in some way. This prevents itself from being called in an infinitely recursive manner (and so bringing your server to its knees).
- Start to make use of the use keyword.
The solution
For the anonymous function to be able to call itself recursively, we need to ensure that it has a reference to itself that it is able to call. Thus, our solution, which makes use of a closure:
$maximum = 5; // This can be adjusted to as many levels as necessary. $func = function($level = 0) use ($maximum, &$func) echo str_repeat(' ', $level) . "I am on level $level>\n"; if ($level $maximum) $func($level + 1); > >; $func();
A final note
Notice how the function references itself — using a variable reference. Why is this necessary?
As the $func variable is being used in the declaration of the anonymous function, it is not yet populated at declaration time. Passing it as a reference, we are able to ensure that by the time the function is executed, the $func variable would have been populated with our anonymous function.