【问题标题】:Load functions dynamically into class from external file将函数从外部文件动态加载到类中
【发布时间】:2009-04-08 06:17:21
【问题描述】:

是否可以在 php 中加载函数,例如从外部文件中加载到类中。 我正在尝试为辅助函数创建一个加载器,以便我可以调用:

$registry->helper->load('external_helper_function_file');

之后它应该能够像这样调用文件中的函数:

$registry->helper->function();

感谢您的帮助

【问题讨论】:

  • $registry 只是一个用于存储全局访问的函数和变量的类。

标签: php class


【解决方案1】:

抛开意见,这是很好的 OOP 设计。即使使用当前版本的 PHP 也是可能的,尽管不像 PHP5.3 那样干净。

class Helper {
    /* ... */
    function load($file) {
      include_once($file);
    }
    function __call($functionName, $args) {
       if(function_exists($functionName))  
         return call_user_func_array($functionName, $args);
    }

}

【讨论】:

  • 您可能想使用 call_user_func_array(),在您的示例中,该函数将在一个数组参数中传递所有参数
  • 这正是我想要的
  • 在包含的文件中运行的范围不保留在类中。这些函数可以在它们之外运行。
【解决方案2】:

好的,第一,我同意这是不礼貌的。此外,在 5.3 中,您可以使用带有 __call 魔术字的新闭包语法来将运算符用作函数(JS 风格)。

现在,如果我们想提供一种按照您的方式执行此操作的方法,我可以考虑使用 create_fnuction 和 __call 魔法。

基本上,您使用正则表达式模式将函数转换为兼容的字符串,并将它们放在私有成员中。比你使用 __call 方法来获取它们。我正在做一个小演示。

好的,课程就到这里。我从几周前看到的一个使用闭包来实现 JS 样式对象的课程中获得灵感:

/**
 * supplies an interface with which you can load external functions into an existing object
 * 
 * the functions supplied to this class will recive the classes referance as a first argument, and as 
 * a second argument they will recive an array of supplied arguments.
 * 
 * @author arieh glazer <arieh.glazer@gmail.com>
 * @license MIT like 
 */
class Function_Loader{
    /**
     * @param array holder of genarated functions
     * @access protected
     */
    protected $_funcs = array();

    /**
     * loads functions for an external file into the object
     * 
     * a note- the file must not contain php tags.
     * 
     * @param string $source a file's loaction
     * 
     * @access public
     */
    public function load($source){
        $ptrn = '/function[\s]+([a-zA-Z0-9_-]*)[\s]*\((.*)\)[\s]*{([\w\s\D]+)}[\s]*/iU';
        $source = file_get_contents($source);
        preg_match_all($ptrn,$source,$matches);
        $names = $matches[1];
        $vars = $matches[2];
        $funcs = $matches[3];
        for ($i=0,$l=count($names);$i<$l;$i++){
            $this->_funcs[$names[$i]] = create_function($vars[$i],$funcs[$i]);
        }
    }

    public function __call($name,$args){
        if (isset($this->_funcs[$name])) $this->_funcs[$name]($this,$args);
        else throw new Exception("No Such Method $name");
    }
}

limitations- 1st,源不能有任何 php 标签。第二,功能永远是公开的。第三——我们只能模仿$this。我所做的是作为第一个参数 $this 传递,第二个是参数数组(这是第四个限制)。此外,您将无法从类中访问非公共成员和方法。 源文件示例:

function a($self,$arr=array()){
    //assuming the object has a member called str
    echo $self->str;
}

这对我来说是一个有趣的练习,但总的来说是一种不好的做法

【讨论】:

    【解决方案3】:

    所以你想不只是include 一个文件,而是include 它进入一个对象的范围?

    ...

    我认为你的做法是错误的。如果registry 对象有一系列具有自己功能的助手成员,则更有意义。最终结果可能如下所示:

    $registry->aHelper->aFunction();
    $registry->aDifferentHelper->aDifferentFunction();
    

    仔细使用 {} 语法,您应该能够将成员对象动态添加到您的上帝对象。

    此时值得注意的是,god object 几乎是不变的anti-pattern。如果您在全局范围内需要这些功能,请使用引导包含技术,然后将其置于全局范围内。如果您需要传递该数据,则可以根据需要将其传递给函数,或者将其存储在数据库中并在其他地方检索。

    我知道上帝之物真的看起来是个好主意,但我向你保证,它以后会让事情变得一团糟。

    【讨论】:

    • 感谢您的意见。这些辅助函数可能会不断增加。所以我希望它们只在需要时加载。如果有人能指出正确的方向,那就太好了。 CI 助手之类的东西
    • 我可以建议你打开 CodeIgniter 代码库吗?如果这是您的想法模型,那么这听起来是一个不错的起点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-27
    • 2011-12-24
    • 1970-01-01
    • 2020-06-05
    • 2012-09-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多