7

I am just starting out with PHP, and I am wondering if there is a way to add an anonymous function to a class instance.

For instance, lets say...

class A{
    public B;
}

$c = new A();

//This is where I am getting a little confused...
//The following wont work

$c->B = function(){echo('HelloWorld');};
$c->B();

What I am hoping to do is reuse the same spit of code in a great number of different applications, and make it so that I can just 'swap-out' and replace functions in specific instances.

I am using php5.3 (so anonymous functions should work, just not in the way that I am using them).

Thanks so very much for your time!!

-GK

geekay
  • 107
  • 2
  • 7
  • Can you go into detail about these different applications you are trying to implement? I'm thinking that simple inheritance could be a better solution, but more information would be helpful. –  Jun 13 '10 at 22:02
  • Possible duplicate: http://stackoverflow.com/questions/2938004/how-to-add-a-new-method-to-a-php-object-on-the-fly – dev-null-dweller Jun 13 '10 at 22:15
  • GK here, @Tim Cooper I am working on a server side for a game that I am working on, and the server is going to be made up of dozens and dozens of applications that will manage different parts of the game. They all will be very similar, and be using many of the same classes, however they will all need the ability to execute custom functions... Abstract I know,... Thanks for your help! @dev-null-dweller I think your right, I tried looking up this issue first, but obviously I didnt look hard enough, Thanks!! – geekay Jun 14 '10 at 01:00

7 Answers7

10

You can use the __call magic function for this job. Not a beauty, but it works..

like this:

class A {
    public $B;

    public function __call($closure, $args)
    {
        call_user_func_array($this->$closure, $args);
    }
}

$c = new A();

$c->B = function () { echo('HelloWorld'); };
$c->B();
Artefacto
  • 96,375
  • 17
  • 202
  • 225
therufa
  • 2,050
  • 2
  • 25
  • 39
  • gk Here, I will look into this... I will need to figure out what is does... Thanks so very much for pointing me in the right direction! – geekay Jun 14 '10 at 01:01
  • edited to revert the downvote. I saw you posted the exact same solution as user358390 (minus a minor difference), but I hadn't noticed the times were so close, so I'm giving the benefit of the doubt – Artefacto Jun 14 '10 at 08:06
5

FWIW:

PHP 5.3's treatment of anonymous functions is entertaining. This won't work:

$c->B = function() { echo func_get_arg(0); };
$c->B("This fails :(");

This WILL work:

$c->B = function() { echo func_get_arg(0); };
$hilarious = $c->B;
$hilarious("This works!");

To work around this, you need to use a __call hack like the one provided by Oden.

This behavior may change in the future. The array dereferencing RFC was recently committed to PHP's trunk, and the patch has set off a discussion on function call chaining, the syntax of which may allow what you're trying to do without the __call hack. Unfortunately it's proven difficult in the past to get function call chaining working.

Community
  • 1
  • 1
Charles
  • 50,943
  • 13
  • 104
  • 142
4
# real ugly, but PoC...

class a {
  function __call($f, $x) {
    call_user_func_array($this->$f, $x);
  }
}

$a = new a;
$a->b = function() { echo "Hello world"; };
$a->b();
user358390
  • 627
  • 4
  • 4
2

Sounds like you are describing a Strategy Pattern or Decorator Pattern - there are other ways to achieve this in way which is more easily communicated with other developers who read your code.

Paul Dixon
  • 295,876
  • 54
  • 310
  • 348
1

You can do something along these lines (which will also work with callbacks that are not closures):

<?php
class A {
    private $fun;
    function setFun($fun) {
        if (!is_callable($fun))
            throw new InvalidArgumentException();
         $this->fun = $fun;
    }
    public function fun() {
        call_user_func_array($this->fun, func_get_args());
    }
}

$c = new A();

$c->setFun(function($a) { echo('HelloWorld ' . $a);});
$c->fun("here");

which gives HelloWorld here.

That said, you should also consider inheritance or the decorator pattern.

Artefacto
  • 96,375
  • 17
  • 202
  • 225
1

This is not an issue anymore by PHP 7;

// no error
$result = ($this->anonFunc)();
$result = ($this->anonFunc)($arg1, $arg2, ...);

See more about AST.

Kerem
  • 11,377
  • 5
  • 59
  • 58
0

Rather than hooking a __call magic method into your class, you can instead execute the callable directly using call_user_func.

class A {
    public $b;
}

$c = new A();
$c->b = function(){echo('HelloWorld');};

call_user_func($c->b);    // HelloWorld

Obviously it would be nice for PHP to provide some syntax to execute this directly.

Lee Davis
  • 4,685
  • 3
  • 28
  • 39