Php 调用\u user\u func\u数组,将参数传递给构造函数
我在stackoverflow上搜索了很多谷歌搜索结果页面,但找不到适合我的解决方案。我试图构建的函数中似乎只有最后一个障碍,它使用call\u user\u func\u数组来动态创建对象 我得到的可捕获致命错误是类Product的Php 调用\u user\u func\u数组,将参数传递给构造函数,php,mysql,oop,constructor,Php,Mysql,Oop,Constructor,我在stackoverflow上搜索了很多谷歌搜索结果页面,但找不到适合我的解决方案。我试图构建的函数中似乎只有最后一个障碍,它使用call\u user\u func\u数组来动态创建对象 我得到的可捕获致命错误是类Product的对象无法转换为字符串。当错误发生时,在日志中我会得到其中五个(每个参数一个):PHP警告:产品缺少参数1::\uu construct(),,在可捕获的致命错误之前 这是函数的代码: public static function SelectAll($class,
对象无法转换为字符串。当错误发生时,在日志中我会得到其中五个(每个参数一个):PHP警告:产品缺少参数1::\uu 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\u user\u func\u array
中实际使用我的$args
数组之前,一切都是绝对正常的
调用该数组是否有一些我遗漏的微妙细节?我读过一次关于call_user_func_array的PHP手册,然后读了一些,该页面上的示例似乎向人们展示了如何构建一个数组,并在第二个参数中调用它。我可能做错了什么?您不能像这样调用$class
的构造函数:
call_user_func_array (new $class, $args);
这不是第一个参数。让我们把它分开:
call_user_func_array (new $class, $args);
与
$obj = new $class;
call_user_func_array ($obj, $args);
如您所见,$class
的构造函数在call\u user\u func\u array
生效之前已经被调用。由于没有参数,您会看到以下错误消息:
Missing argument 1 for Product::__construct()
Object of class Product could not be converted to string.
其次,$obj
是object类型。有效的回调必须是字符串或数组(或者是非常特殊的对象:,但这不在讨论范围之内,我只是为了完整性而命名它)
由于$obj
是一个对象,不是有效的回调,因此您会看到PHP错误消息:
Missing argument 1 for Product::__construct()
Object of class Product could not be converted to string.
PHP尝试将对象转换为字符串,这是不允许的
因此,正如您所看到的,您无法轻松地为构造函数创建回调,因为对象还不存在。也许这就是为什么你不能很容易地在手册中找到它
构造函数在这里需要一些特殊处理:如果需要将变量参数传递给尚未初始化对象的类构造函数,可以使用:
$ref = new ReflectionClass($class);
$new = $ref->newInstanceArgs($args);
请参见不可能使用调用用户函数数组()
,因为(顾名思义)它调用函数/方法,但不用于创建对象,请使用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);
在我看来,它更干净,因为更少的魔法和更多的控制我将其用于单例工厂模式,因为ReflectionClass破坏了依赖树,我讨厌使用eval,但这是我发现的唯一简化使用singleton模式来注入mockObjects的方法,其中PHPUnit没有打开该注入的类方法,小心传递给eval函数的数据!!!!!!!!您必须确保已清洁和过滤
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];
}
}
要实例化对象,请执行以下操作:
$myVar= MyClass::getInstance($objetFromClassMyDependInjection);
它调用带有参数的构造函数。我知道扩展静态方法getInstance可以得到相同的结果,但通过这种方式进行团队合作更容易使用谢谢你的回答,但是,我没有收到“无效回调”错误,错误日志似乎表明调用用户函数数组
确实成功调用了该构造,因为它给了我一个PHP警告:Product::\uu construct()
缺少参数1,对于特定构造函数期望的五个参数中的每一个,但由于某种原因没有收到。当然,这可能是我还不了解的东西,但这是我目前掌握的知识。您首先使用new$class
实例化对象。这意味着构造函数在调用用户函数数组之前就已经被调用了。看到了吗?首先是new
,因为您将其用作参数中的表达式,然后会发生函数调用。但是由于执行了new,已经调用了$class
的构造函数(没有参数)。然后PHP尝试将对象转换为字符串,因为第一个参数需要字符串或数组。因为您的对象不支持对字符串进行强制转换,所以您会收到错误/警告。我明白了!非常感谢。我将研究动态地将参数传递给构造函数的其他方法。@tuespetre:请参阅答案中的代码示例(最后的两行代码),这是您可以做到的方法。我现在理解了ReflectionClass的这一点。非常感谢你的回答。我现在可以做我需要的!例如,您的意思是可以调用Product::u-construct($args)
,其中$args
是一个参数数组?所有函数都可以用这样的参数数组调用吗?我在哪里说过这样的话?!?当然,您可以使用数组实例化对象,但随后将在构造函数中以单个参数的形式接收该数组。看起来这不是你想要的。对不起,我看错了你的帖子ReflectionClass方法更干净,因为您的方法不会缩放到超过4个参数。不过,您的方法在执行时间上会更快。@demonkoryu有人可能会说,使用反射本身就是一种黑客行为,但您当然是对的,每次签名更改时都需要特殊的方法。然而,这种特殊的方法是如此普遍,以至于它们甚至有一个名字:工厂:)另一方面,答案是从2011年开始的,现在有了variadics,如果你认为这样做是一个好主意,那么创建一个通用工厂“东西”是微不足道的。