call_user_func_array将参数传递给构造函数

时间:2011-11-05 20:54:34

标签: php mysql oop constructor

我搜索了很多页面的Google搜索结果以及此处的stackoverflow,但找不到适合我情况的解决方案。我似乎只在我正在尝试构建的函数中有一个最后的障碍,它使用call_user_func_array来动态创建对象。

我得到的可捕获的致命错误是Object of class Product could not be converted to string。当错误发生时,在日志中我得到其中五个(每个参数一个):PHP Warning: Missing argument 1 for Product::__construct(),在可捕获的致命错误之前。

这是函数的代码:

public static function SelectAll($class, $table, $sort_field, $sort_order = "ASC")
{  
/* First, the function performs a MySQL query using the provided arguments. */

$query = "SELECT * FROM " .$table. " ORDER BY " .$sort_field. " " .$sort_order;
$result = mysql_query($query);

/* Next, the function dynamically gathers the appropriate number and names of properties. */

$num_fields = mysql_num_fields($result);
for($i=0; $i < ($num_fields); $i++)
{
  $fetch = mysql_fetch_field($result, $i);
  $properties[$i] = $fetch->name;
}

/* Finally, the function produces and returns an array of constructed objects.*/

while($row = mysql_fetch_assoc($result))
{
  for($i=0; $i < ($num_fields); $i++)
  {
    $args[$i] = $row[$properties[$i]];
  }
  $array[] = call_user_func_array (new $class, $args);
}

return $array;
}

现在,如果我注释掉call_user_func_array行并将其替换为:

$array[] = new $class($args[0],$args[1],$args[2],$args[3],$args[4]);

页面按原样加载,并填充我正在构建的表。所以在我尝试在$args内实际使用call_user_func_array数组之前,一切都绝对有用。

是否有一些关于调用我缺少的数组的细微细节?我读了一次call_user_func_array的PHP手册,然后是一些,该页面上的示例似乎向人们展示了构建一个数组并为第二个参数调用它。我能做错什么?

3 个答案:

答案 0 :(得分:20)

你不能像这样调用$class的构造函数:

call_user_func_array (new $class, $args);

第一个参数没有valid callback。让我们分开来看:

call_user_func_array (new $class, $args);

相同
$obj = new $class;
call_user_func_array ($obj, $args);

正如您所看到的,$class的构造函数在call_user_func_array生效之前就已经被调用了。由于它没有参数,您会看到以下错误消息:

Missing argument 1 for Product::__construct()

接下来,$obj属于object类型。有效的回调必须是字符串或数组(或者特别是一个非常特殊的对象:Closure,但这里没有讨论,我只是为了完整而命名。)

由于$obj是一个对象而不是有效的回调,因此您会看到PHP错误消息:

Object of class Product could not be converted to string.

PHP尝试将对象转换为字符串,但不允许这样做。

正如您所看到的,您无法轻松地为构造函数创建回调,因为该对象尚不存在。也许这就是为什么你不能轻易地在手册中查找它。

构造函数需要在这里进行一些特殊处理:如果需要将变量参数传递给not-yet initialize对象的类构造函数,可以使用ReflectionClass来执行此操作:

  $ref = new ReflectionClass($class);
  $new = $ref->newInstanceArgs($args);

请参阅ReflectionClass::newInstanceArgs

答案 1 :(得分:2)

使用call_user_func_array()是不可能的,因为(顾名思义)它调用函数/方法,但不打算创建对象,使用ReflectionClass

$refClass = new ReflectionClass($class);
$object = $refClass->newInstanceArgs($args);

另一种(更基于设计的)解决方案是静态工厂方法

class MyClass () {
  public static function create ($args) {
    return new self($args[0],$args[1],$args[2],$args[3],$args[4]);
  }
}

然后只是

$object = $class::create($args);

在我眼里,它更干净,因为更少的魔法和更多的控制

答案 2 :(得分:-1)

我使用这个用于singleton工厂模式,因为ReflectionClass打破了依赖树,我讨厌使用eval但它是我找到简化使用singleton模式注入mockObjects的唯一方法,用PHPUnit whitout打开类方法对于那次注射,要小心你的数据通过评估功能!!!!!!!!你必须确保清洁和过滤!!!

c.C_ID IN (22, 23, 24)

使用它:

abstract class Singleton{
   private static $instance=array();//collection of singleton objects instances
   protected function __construct(){}//to allow call to extended constructor only from dependence tree
   private function __clone(){}//to disallow duplicate
   private function __wakeup(){}//comment this if you want to mock the object whith php unit jejeje

   //AND HERE WE GO!!!
   public static function getInstance(){        
    $a=get_called_class();
    if(!array_key_exists($a, self::$instance)){ 
        if(func_num_args()){
          /**HERE IS THE CODE **//
            $args=func_get_args();
            $str='self::$instance[$a]=new $a(';
            for($i=0;$i<count($args);$i++){
                $str.=(($i)?",":"").'$args['.$i.']';
            }
            eval($str.");");//DANGER, BE CAREFULLY...we only use this code to inject MockObjects in testing...to another use you will use a normal method to configure the SingletonObject
          /*--------------------------*/
        }else{
            self::$instance[$a]=new $a();
        }

    }
    return self::$instance[$a];     
}


}

实例化对象:

class MyClass extends Singleton{
    protected function __construct(MyDependInjection $injection){
      //here i use the args like a normal class but the method IS PROTECTED!!! 
  }
}

它调用构造函数,而不是我所使用的args。我知道我可以得到相同的结果扩展静态方法getInstance,但团队合作更容易使用这种方式