OOP PHP - 动态构建/运行对象和函数名称

时间:2009-09-04 18:54:56

标签: php oop

我有一个“最佳实践”问题。我正在用PHP开发一个OO MVC框架,并且大多数类很容易交互 - 它们在代码中逐字声明并被使用。例如:

// In class 'getDetails'
$db = new mysqli(.....);
$db->query(.....);

但是,有时会动态构建类和函数名称。实际的类文件都是在框架中创建和定位的,但它们并非都是字面上声明和使用的。直到运行时,框架才知道完成请求所需的类;所以通常会创建类和函数名并将其存储在变量中。在最简单的情况下,变量用于创建对象并运行函数。例如:

$request = 'blog'; 
$action = 'view';
$class = new $request(); // Creates an blog object
$class->$action(); // Runs the blog function view

但是,我在尝试使用变量来运行静态函数时遇到过这种情况(here是堆栈溢出问题和答案),其中变量无法在文字用法中使用
($ request :: $ action()给出解析错误)。我已经在PHP手册中看到了用于交互/使用类,函数和对象的函数,但之前没有必要处理它们。

我的问题是在动态创建类和函数名的情况下处理和运行类和函数的最佳方法是什么?

3 个答案:

答案 0 :(得分:4)

您提到的两种方法都很好但有一些限制:

使用常规表示法:

$request = 'blog'; 
$action = 'view';
$class = new $request(); // Creates an blog object
$class->$action(); // Runs the blog function view

使用符号实例化类要求您事先知道每个类/方法接受的参数。所以你不能设计一个可以接受任意参数的factory pattern

使用call_user_func_array()可以使用任意参数。

$request = 'blog'; 
$action = 'view';
$params = array(
   $_GET['category'],
   $_GET['limit']
);
call_user_func_array(array($request, $action), $params);

所以上面的代码等同于文字:

blog::view($_GET['category'], $_GET['limit']);

基本上,call_user_func_array()展平数组$ params,将其中的每个值作为参数传递给方法blog :: view()。

对动态/对象方法调用执行相同的操作:

call_user_func_array(array(new $request, $action), $params);

但是,这并没有解决创建任意类的实例并向其传递任意数量的参数的问题。为此,您可以使用ReflectionClass

示例:

$request = 'blog';
$action = 'view';
$configs = array('something', 'something else');
$params = array(
   $_GET['category'],
   $_GET['limit']
);
$instance = call_user_func_array(
   array(new ReflectionClass($request), 'newInstance'), 
   $configs
);
$return = call_user_func_array(array($instance, $action), $params);

这相当于:

$configs = array('something', 'something else');
$params = array(
   $_GET['category'],
   $_GET['limit']
);
$blog = new blog($configs[0], $configs[1]);
$blog->view($_GET['category'], $_GET['limit']);

使用这些工具,您可以动态地实例化任意对象,并将任意数量的参数传递给它们的__constructor()以及任何方法。

如果您在功能方面表示最佳,请使用call_user_func_array()和ReflectionClass()。 如果您在性能方面表现最佳,请不要担心。良好的设计和功能可以提高性能。

答案 1 :(得分:0)

我不确定我是否理解你,但您可以使用factory design pattern

答案 2 :(得分:0)

如果我正确理解了您的问题,那么我会使用eval。您也可以为静态功能执行此操作。例如,以下是我几年前建立的网站的一些代码。

function StaticObjectPrint($mysql,$template, $objecttype, $debug=0) {
    foreach(eval("return $objecttype::ReturnStaticVariablesForPrinting(\$mysql);") as $key => $value) {
        global $$key;
        $$key = $value;
    }
    if($debug==1)
        print_r ($GLOBALS);

    return ParsePlainTextFile($template,1);
}

在这种情况下,有几个不同类的对象,但它们都有一个ReturnStaticVariablesForPrinting函数。根据用户单击的对象类型,它将返回有关该对象的一些静态信息,而不必实例化每个对象(并占用一堆内存)。这对于生成对象属性列表很有用。 (我意识到这违反了一些OO原则,但速度是必要的)