在PHP中动态创建实例方法

9
我希望你能够在类的构造函数中动态创建实例方法,就像这样:

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 

问题似乎是lambda_2函数对象在构造函数中没有与$this绑定。任何帮助都将不胜感激。

你可能想要清理构造函数代码中的错误。 - Gordon
2个回答

19

你将匿名函数赋值给一个 属性,但是却试图使用该属性名称调用一个 方法。PHP无法自动从该属性中取消引用匿名函数。下面的代码可以正常工作:

class Foo{

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

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

您可以利用神奇的__call方法来拦截无效的方法调用,以查看是否存在一个包含回调/匿名函数的属性:

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

从PHP5.3开始,您也可以使用Lambda创建匿名函数

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

更多相关信息,请参见PHP匿名函数手册


3
为了完整起见,在这种方式中使用create_function将在每次构造类时在全局空间创建一个lambda函数,并且将保留在内存中,没有垃圾回收的好处(例如当对象未设置时)。它可以工作,但要小心使用。 - webbiedave
2
为了更加完整,create_function 并不像 lambda 一样创建任何东西 - 它基本上是一个被美化的 eval,它创建了一个函数,使得没有“真正”的函数可能会发生冲突。除非你需要与 PHP<5.3 兼容,否则应该尽可能避免使用它。 - IMSoP

3
你可以使用 __call魔术方法来调用运行时实例方法。
class Foo
{
    public function __call($name, $args) 
    {
        if ($name == 'myFunc') {
            // call myFunc
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接