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

<?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");

 

0 0 vote
Article Rating
Share this: