25

I'd like to iterate over an array and dynamically create functions based on each item. My pseudocode:

$array = array('one', 'two', 'three');

foreach ($array as $item) {
    public function $item() {
        return 'Test'.$item;
    }
}

How should I go about doing this?

Tom
  • 927
  • 3
  • 12
  • 20
  • 4
    Can i ask why you want to create this functions – Baba Oct 12 '12 at 22:41
  • Adding too much dynamic can make a program unreadable - which is equivalent to unmaintainable. Can you go into details of what you have and what you want to get? – Sven Oct 13 '12 at 00:46
  • 1
    possible duplicate of [Dynamically Create Instance Method in PHP](http://stackoverflow.com/questions/3231365/dynamically-create-instance-method-in-php) – Luís Cruz May 29 '15 at 10:03
  • 1
    @Baba and Sven Simple, he is asking a good point because some functions seems to be same with only difference of one word. We are duplicating the code. So best way is write a dynamic code. – Abhi Nov 28 '17 at 10:17

2 Answers2

33

Instead of "creating" functions, you can use the magic method __call(), so that when you call a "non-existent" function, you can handle it and do the right action.

Something like this:

class MyClass{
    private $array = array('one', 'two', 'three');

    function __call($func, $params){
        if(in_array($func, $this->array)){
            return 'Test'.$func;
        }
    }
}

Then you can call:

$a = new MyClass;
$a->one(); // Testone
$a->four(); // null

DEMO: http://ideone.com/73mSh

EDIT: If you are using PHP 5.3+, you actually can do what you are trying to do in your question!

class MyClass{
    private $array = array('one', 'two', 'three');

    function __construct(){
        foreach ($this->array as $item) {
            $this->$item = function() use($item){
                return 'Test'.$item;
            };
        }
    }
}

This does work, except that you can't call $a->one() directly, you need to save it as a variable.

$a = new MyClass;
$x = $a->one;
$x() // Testone

DEMO: http://codepad.viper-7.com/ayGsTu

Community
  • 1
  • 1
gen_Eric
  • 223,194
  • 41
  • 299
  • 337
  • @NullUserException: Thanks for adding the fact that `__call()` is a "magic method". – gen_Eric Oct 12 '12 at 22:49
  • You can also use the magic `__get()` function to call closures / callbacks functions then:, see [Dynamically Create Instance Method in PHP](http://stackoverflow.com/questions/3231365/dynamically-create-instance-method-in-php) - If you really think `__call()` or `__get()` is what has been asked for, please suggest an existing question as a duplicate. – hakre Oct 12 '12 at 23:44
  • 1
    How can you PHP docblock this so editor does not warn about "non existing functions"? – Kyslik Sep 06 '16 at 15:13
4
class MethodTest
{
    private $_methods = array();

    public function __call($name, $arguments)
    {
        if (array_key_exists($name, $this->_methods)) {
            $this->_methods[$name]($arguments);
        }
        else
        {
            $this->_methods[$name] = $arguments[0];
        }
    }
}

$obj = new MethodTest;

$array = array('one', 'two', 'three');

foreach ($array as $item) 
{
    // Dynamic creation
    $obj->$item((function ($a){ echo "Test: ".$a[0]."\n"; }));
    // Calling
    $obj->$item($item);
}

The above example will output:

Test: one
Test: two
Test: three
quAnton
  • 776
  • 6
  • 10
  • is there a way to get around the `$a[0]` and to just have `$a` ? – duck Jun 21 '17 at 15:53
  • @duck class MethodTest { public function __call($name, $arguments) { echo "" . "Method: ".$name."\n" . (!empty($arguments) ? "Parameters: ". implode(', ', $arguments) : "No parameter!"). "\n"; } } $obj = new MethodTest; $obj->ExecTest('par 1', 'par 2', 'others ...'); $obj->ExecTest(); – quAnton Jun 26 '17 at 09:57