tags:

views:

34

answers:

2

I'd like to be able to dynamically create an instance method within a class' constructor like so:

class Foo{
   function __construct() {
      $code = 'print hi;';
      $sayHi = create_function( '', $code);
      print "$sayHi"; //prints lambda_2
      print $sayHi(); // prints 'hi'
      $this->sayHi = $sayHi; 
    }
}

$f = new Foo;
$f->sayHi(); //Fatal error: Call to undefined method Foo::sayHi() in /export/home/web/private/htdocs/staff/cohenaa/dev-drupal-2/sites/all/modules/devel/devel.module(1086) : eval()'d code on line 12 

The problem seems to be that the lambda_2 function object is not getting bound to $this within the constructor.

Any help is appreciated.

+1  A: 

You can use the __call magic method to employ run-time instance methods.

class Foo
{
    public function __call($name, $args) 
    {
        if ($name == 'myFunc') {
            // call myFunc
        }
    }
}
webbiedave
+3  A: 

You are assigning the anonymous function to a property, but then try to call a method with the property name. PHP cannot automatically dereference the anonymous function from the property. The following will work

class Foo{

   function __construct() {
      $this->sayHi = create_function( '', 'print "hi";'); 
    }
}

$foo = new Foo;
$fn = $foo->sayHi;
$fn(); // hi

You can utilize the magic __call method to intercept invalid method calls to see if there is a property holding a callback/anonymous function though:

class Foo{

   public function __construct()
   {
      $this->sayHi = create_function( '', 'print "hi";'); 
   }
   public function __call($method, $args)
   {
       if(property_exists($this, $method)) {
           if(is_callable($this->$method)) {
               return call_user_func_array($this->$method, $args);
           }
       }
   }
}

$foo = new Foo;
$foo->sayHi(); // hi

As of PHP5.3, you can also create Lambdas with

$lambda = function() { return TRUE; };

See the PHP manual on Anonymous functions for further reference.

Gordon
For completeness, using create_function in this way will create a lamda function in the global space each time the class is constructed and will remain in memory without the benefits of garbage collection (when object is unset for example). It'll work, but use with care.
webbiedave