Earlier, this week, one of my co-workers was working on a personal project in which he wanted to use a function to set a variable number of parameters to zero.
[php]// he wanted this:
$a = 1; $b = 2; $c = 3;
set_to_zero($a, $b, $c);
echo "$a $b $c"; // prints "0 0 0";
?>[/php]
His first impulse was to use func_get_args(). But this wasn't working for him. Turns out function_get_args() returns a COPY of the arguments, and not a reference. The manual didn't lean either way or the other, so I updated it.
A few mails bounced around our internal developer's list. It seems that there's no non-hack way to do this.
Here's what we came up with:
[b]Non-Solution #1[/b]
[php]function set_array_to_zero(&$array)
{
foreach ($array AS $k => $v) {
$array[$k] = 0;
}
}
$a = 1; $b = 2; $c = 3;
set_array_to_zero(array(&$a, &$b, &$c));
echo "$a $b $c"; // prints "0 0 0";
?>[/php]
This WORKS, and is probably the most "proper" way to do this, but the semantics violate his original requirements.
A couple other non-semantic-repecting solutions were proposed (one using $obj = new StdClass;), but nothing that really worked the way he intended.
Here's one that seems pretty close, on the surface:
[b]Non-Solution #4[/b]
[php]function set_var_to_zero($var)
{
for ($i=0; $i
}
}
$a = 1; $b = 2; $c = 3;
set_var_to_zero('a', 'b', 'c');
echo "$a $b $c"; // prints "0 0 0";
?>[/php]
Sure, it breaks semantics, again, but there's another major problem -- scope:
[b]Non-Solution #5[/b]
[php]function set_var_to_zero($var)
{
for ($i=0; $i
}
}
function foo()
{
$a = 1; $b = 2; $c = 3;
set_var_to_zero('a', 'b', 'c');
echo "$a $b $c"; // actually prints "1 2 3";
}
$a = 4; $b = 5; $c = 6;
foo();
?>[/php]
Since there's no way to operate on an intermediate scope (only local symbols and global symbols), at least in a functional context, this approach is a dead end.
Finally, after sleeping on it, I came up with this:
[b]Non-Solution #16[/b]
[php]error_reporting(E_ALL);
define('STZ_MAX_ARGUMENTS', 1023);
$set_to_zero = create_function(
'&$a'. implode(',&$a', range(0, STZ_MAX_ARGUMENTS)),
'for ($i=0; $i <= STZ_MAX_ARGUMENTS; $i++) ${"a$i"} = 0;'
);
$a = 1; $b = 2; $c = 3;
@$set_to_zero($a, $b, $c);
echo "$a $b $c"; // prints "0 0 0";
?>[/php]
This ALMOST works -- I mean, it's REALLY close. The semantics are still a LITTLE off -- the $ I can live with. The @error_suppressor is also necessary, because it seems that it's not possible to pass default values to create_function(...) (try removing the @ -- you'll get (1024 - actual_number_of_arguments) error messages). There's also the issue of limiting the number of arguments to an arbitrary number. The way I see it, no developer should be working on > 1000 (actually, even that is entirely too many), anyway.
So, without resorting to eval / writing to a file + include, this is the best solution we could come up with.
Personally, I'd alter my requirements to go with the array-passing approach.
S
Your friends got to much of your time to waste :)
$a = $b = $c = $d = 0;
is actually less typing, and works....
Oh, thank you.
Your solution on how to set variables to zero is amazing, and would surely be a useful one if only it were in response to something along the lines of "How do I set variables to zero" and not "How do I pass variable arguments by reference."
Thanks again.
Great article thanks ! Boy that Alan Knowles is not a fast one ... :D
I'd like to mention that there's a small mistake in one of your functions which follows the correct version :
function set_var_to_zero($var)
{
for ($i = 0; $i func_num_args(); $i++) {
$GLOBALS[func_get_arg($i)] = 0;
}
}