This question already has an answer here:
I have searched many a page of Google results as well as here on stackoverflow but cannot find a solution that seems to fit my situation. I appear to have but one last snag in the function I am trying to build, which uses call_user_func_array to dynamically create objects.
The catchable fatal error I am getting is Object of class Product could not be converted to string
. When the error occurs, in the log I get five of these (one for each argument): PHP Warning: Missing argument 1 for Product::__construct(),
before the catchable fatal error.
This is the code of the function:
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;
}
Now, if I comment out the call_user_func_array line and replace it with this:
$array[] = new $class($args[0],$args[1],$args[2],$args[3],$args[4]);
The page loads as it should, and populates the table I am building. So everything is absolutely functional until I try to actually use my $args
array within call_user_func_array
.
Is there some subtle detail about calling that array that I am missing? I read the PHP manual for call_user_func_array once, and then some, and examples on that page seemed to show people just building an array and calling it for the second argument. What could I be doing wrong?
I use this for singleton factory pattern, becouse the ReflectionClass brokes the dependence tree, I hate the use of eval but its the only way to i find to simplificate the use of singleton pattern to inject mockObjects whith PHPUnit whitout open the class methods to that injection, BE CAREFULL WHITH THE DATA WHAT YOU PASS TO eval FUNCTION!!!!!!!! YOU MUST BE SURE THAT IS CLEANED AND FILTERED!!!
And to use that:
to instanciate the object:
it calls the constructor whith the args I pased. i know that i can get the same result extending the static method getInstance but to teamworking its more easy to use this way
Not possible using
call_user_func_array()
, because (as the name suggest) it calls functions/methods, but is not intended to create objects, UseReflectionClass
Another (more design-based) solution is a static factory method
and then just
In my eyes it's cleaner, because less magic and more control
You can't call the constructor of
$class
like this:That's no valid callback as first parameter. Let's pick this apart:
Is the same as
As you can see, the constructor of
$class
has been already called beforecall_user_func_array
comes into action. As it has no parameters, you see this error message:Next to that,
$obj
is of type object. A valid callback must be either a string or an array (or exceptionally a very special object:Closure
, but that's out of discussion here, I only name it for completeness).As
$obj
is an object and not a valid callback, so you see the PHP error message:PHP tries to convert the object to string, which it does not allow.
So as you can see, you can't easily create a callback for a constructor, as the object yet not exists. Perhaps that's why you were not able to look it up in the manual easily.
Constructors need some special dealing here: If you need to pass variable arguments to a class constructor of a not-yet initialize object, you can use the
ReflectionClass
to do this:See
ReflectionClass::newInstanceArgs