HOWTO use closure functions as array values in a class in PHP 5.4
Let’s say i got an array with anonymous functions in PHP 5.4:
$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'
When but when you stick the functions in a class
class Say {
private $fns = [
"hello" => function($name, $name2 = false) {
echo empty($name2) ? "Hello $name" : "Hello $name and $name2";
},
"bye" => function($name) {
echo "Bye $name";
}
];
function __construct() {
foreach ($this->fns as $fn) {
call_user_func_array($fn, func_get_args());
}
}
}
$say = new Say("foo");
$say = new Say("foo", "bar");
You get a parse error when defining the array
PHP Parse error: syntax error, unexpected 'function' (T_FUNCTION)
Apparently defining ‘dynamic’ content in a class doesn’t work.
The solution: either add the array in the constructor:
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");
Et voila, a nice way to write flexible PHP!
BONUS: 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");
Leo
That was helpful. Just googled for exactly this case and found the essential “defining ‘dynamic’ content in a class doesn’t work”.
Thanks!
Anonymous
Please fix the css for your font/spacing on your code sections. My OC-ness is attacking me.
Anonymous
Hey quick fix on your code spacing issue on this page (and probably whole blog), add ‘line-height: 1.5′ to your code sections’ CSS.
Php Programmer
This was a great article with lots of good examples and resources. Thanks,
beginner
this is so great