1. PHP Fun - Variable Arguments Be Reference?

    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] [/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:

    Non-Solution #1

    [php] $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: Non-Solution #4

    [php] [/php]

    Sure, it breaks semantics, again, but there's another major problem -- scope: Non-Solution #5

    [php] [/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:

    Non-Solution #16

    [php] [/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.

    7 Responses

    Feed for this Entry
    • 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;
      }
      }

    • The following works for your requirements, as long as argument list is kept at a realistic length.
      You can test it on this code pad: http://codepad.org

      ===========

    • I enclosed the code in php tags in my previous posts and it looks like it wasn't escaped properly. So here it is again:

      [PHP]

      function capitalize(ν
      for ( $i=1; isset( ${"a$i"} ) and ( $arg=∨ $i++ ) {
      if ( !is_null($arg) ) {
      echo "a$i was:".$arg."\n";
      $arg = ucwords($arg);
      } else {
      echo "a$i is NULL \n";
      }
      }
      }

      $one = "i am the one";
      $two = "number two";

      capitalize($one, $two);

      echo "$one\n";
      echo "$two\n";

      [/PHP]

    • It still looks like the code wasnt escaped properly... apparently some trouble with the ampersand.
      Email me and if you want the code.

      Basically you define the function with more arguments ( passed by reference ) that you will ever need, with an incremented argument variables ($arg1, $arg2, $arg3, etc.) and with a default value of null. Then you iterate through them using variable variables : ${"arg$i"} , if the variable is set and not null, modify it and continue loop, otherwise exit loop.

      It works with PHP5. Maybe earlier versions choke on setting a default value on a referenced argument (which doesn't make much sense).