Backend Development

PHP Using Closures in arrays

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
$fns = [
"hello" => function($name, $name2 = false) {
echo empty($name2) ? "Hello $name" : "Hello $name and $name2";
},
"bye" => function($name) {
echo "Bye $name";
}
];
<?php $fns = [ "hello" => function($name, $name2 = false) { echo empty($name2) ? "Hello $name" : "Hello $name and $name2"; }, "bye" => function($name) { echo "Bye $name"; } ];
<?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:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
function say() {
global $fns;
foreach ($fns as $fn) {
call_user_func_array($fn, func_get_args());
}
}
function say() { global $fns; foreach ($fns as $fn) { call_user_func_array($fn, func_get_args()); } }
function say() {
    global $fns;

    foreach ($fns as $fn) {
        call_user_func_array($fn, func_get_args());
    }
}

This works pretty well:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
say("foo");
// 'Hello foo';
// 'Bye foo'
say ("foo", "bar");
// 'Hello foo and bar';
// 'Bye foo'
say("foo"); // 'Hello foo'; // 'Bye foo' say ("foo", "bar"); // 'Hello foo and bar'; // 'Bye foo'
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:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?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");
<?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");
<?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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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");
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");
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:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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");
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");
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");

 

4 1 vote
Article Rating

What's your reaction?

Excited
0
Happy
1
Not Sure
0
Confused
0

You may also like

Subscribe
Notify of
guest


0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments