
Have you ever thought some day how to iterate a list of functions in php. In this tutorial i will show a feature in PHP 5.4 and above related to Closures and arrays which is how to create arrays that contain a Closures. With This feature in place you can iterate an array of functions and execute them one by one.
Let’s demonstrate this with examples
<?php $fns = [ "hello" => function($name, $name2 = false) { echo empty($name2) ? "Hello $name" : "Hello $name and $name2"; }, "bye" => function($name) { echo "Bye $name"; } ];
Now let’s say i want to iterate over all these functions with another function that accepts a variable number of arguments:
function say() { global $fns; foreach ($fns as $fn) { call_user_func_array($fn, func_get_args()); } }
This works pretty well:
say("foo"); // 'Hello foo'; // 'Bye foo' say ("foo", "bar"); // 'Hello foo and bar'; // 'Bye foo'
Remember to use this feature in a class you have to define the array in the constructor:
<?php class Say { private $fns; function __construct() { $this->fns = [ "hello" => function($name, $name2 = false) { echo empty($name2) ? "Hello $name" : "Hello $name and $name2"; }, "bye" => function($name) { echo "Bye $name"; } ]; foreach ($this->fns as $fn) { call_user_func_array($fn, func_get_args()); } } } $say = new Say("foo"); $say = new Say("foo", "bar");
Or (slightly better in terms of readable code) define the functions in the class and reference them from the array
class Say { private $fns = ['hello', 'bye']; function __construct() { foreach ($this->fns as $fname) { $fn = array($this, $fname); call_user_func_array($fn, func_get_args()); } } public function hello($name, $name2 = false) { echo empty($name2) ? "Hello $name" : "Hello $name and $name2"; } public function bye($name) { echo "Bye $name"; } } $say = new Say("foo"); $say = new Say("foo", "bar");
If you don’t want to write out all the methods by hand in the $fns
array you could use this dirty trick to get all function names in the class without the ‘magic’ methods like __construct
and __autoload
:
class Say { function __construct() { $fnames = array_filter(get_class_methods($this), function($name) { return $name[0] != "_"; }); foreach ($fnames as $fname) { $fn = array($this, $fname); call_user_func_array($fn, func_get_args()); } } public function hello($name, $name2 = false) { echo empty($name2) ? "Hello $name" : "Hello $name and $name2"; } public function bye($name) { echo "Bye $name"; } } $say = new Say("foo"); $say = new Say("foo", "bar");