【问题标题】:invoking runtime created functions调用运行时创建的函数
【发布时间】:2013-01-25 13:41:05
【问题描述】:

我正在尝试为我正在处理的项目动态创建数据库实体泛化的基础。我基本上想为扩展它的任何类中的属性动态创建一组标准方法和工具。就像您通过 Python/Django 免费获得的工具一样。

我从这个人那里得到了这个想法:http://www.stubbles.org/archives/65-Extending-objects-with-new-methods-at-runtime.html

所以我已经实现了上面帖子中描述的__call函数,

public function __call($method, $args) {
    echo "<br>Calling ".$method;
    if (isset($this->$method) === true) {
        $func = $this->$method;
        $func();
    }
}

我有一个函数,它通过 get_object_vars 为我提供对象的公共/受保护属性,

public function getJsonData() {
    $var = get_object_vars($this);
    foreach($var as &$value) {
        if (is_object($value) && method_exists($value, 'getJsonData')) {
            $value = $value->getJsonData;
        }
    }
    return $var;
}

现在我想为它们创建一些方法:

public function __construct() {
    foreach($this->getJsonData() as $name => $value) {
        // Create standard getter
        $methodName = "get".$name;
        $me = $this;
        $this->$methodName = function() use ($me, $methodName, $name) { 
            echo "<br>".$methodName." is called";
            return $me->$name; 
        };
    }
}

感谢 Louis H. 在下方指出了“use”关键字。 这基本上会即时创建一个匿名函数。该函数是可调用的,但它不再位于其对象的上下文中。它会产生“致命错误:无法访问受保护的属性”

不幸的是,我绑定到 PHP 5.3 版,它排除了 Closure::bind。因此,Lazy loading class methods in PHP 中建议的解决方案在这里不起作用。

我很困惑……还有其他建议吗?

更新

为简洁而编辑。

【问题讨论】:

  • 你到底为什么要这么做?只需使用公共属性。
  • 尝试使用特征实现此行为,然后 $this 将可用。
  • @Gordon:公开属性将允许其他人直接更改它们,这不是我正在寻找的行为。我想要只读访问权限。
  • 我可能在这里错过了大局。有人真的改变他们吗?毕竟,那些似乎是运行时创建的类。另外,您说您不在对象范围内,并且有公共/受保护的属性。
  • 不,这些类不是运行时创建的。它们是我正在创建的一个小型通用 orm 的一部分。我正在尝试复制制作 python/django 模型的易用性、可读性和可维护性。拥有一组对模型属性进行操作的标准函数是我想要实现的。

标签: php


【解决方案1】:

像这样尝试(你必须使你需要的变量可用于方法)

$this->$methodName = function() use ($this, $methodName, $name){ 
    echo "<br>".$methodName." is called";
    return $this->$$name; 
};

您应该可以通过$this 访问对象上下文。

【讨论】:

  • 产生:致命错误:不能使用 $this 作为词法变量... :-(
  • 但是将 $this 分配给 $me 然后在 use 语句中包含 $me 确实有效。但它显然仍然不在对象上下文中。我收到“致命错误:无法访问受保护的财产”...
  • 即使这个解决方案对我来说不太奏效,但您确实为我指明了正确的方向。因此,我将其标记为正确答案。我已经用解决方案更新了原始问题。
【解决方案2】:

我没有更新上面的原始问题,而是在此处为遇到相同问题的任何人提供完整的解决方案:

首先,由于闭包不能访问真正的对象,我需要在创建闭包函数时在“use”声明中包含实际值(参见上面的原始__construct函数):

$value =& $this->$name;
$this->$methodName = function() use ($me, $methodName, &$value)  { 
    return $value; 
};

其次,__call 魔术方法不仅需要调用闭包函数,它还需要从它返回任何输出。所以我不只是调用 $func(),而是返回 $func();

这成功了! :-)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-15
    • 2012-07-02
    相关资源
    最近更新 更多