

Calling PHP functions with named parameters - maxpert
http://blog.creapptives.com/post/26272336268/calling-php-functions-with-named-parameters
If you need a simpler solution like call_user_func_array you can use this gist.
======
Xcelerate
This is an interesting post. I'm designing a little programming language as a
hobby and I am stuck at how I want to implement function calls.

Without named parameters, you end up with something like the Win32API:

    
    
        ReadSomeFile("file.txt", SOME_FLAG, 0, SOME_OTHER_FLAG, NULL, NULL, CREATE_FILE);
    

This can largely be avoided by structuring your API into little single-purpose
chunks, but it remains a bit of a problem.

Also I think it's somewhat annoying that you have to remember the order of
arguments. In my opinion, this order should not be significant. It leads to a
lot of bugs (for people who don't check the documentation for every method)
with things like:

    
    
        str_replace(needle, haystack)
    

vs

    
    
        str_replace(haystack, needle)
    

It would almost be easier to have everything take a map

    
    
        ajax
            url: "example.com/newwidget"
            method: "post"
            error: -> ...
            success: -> ...
    

But if you enforce this for everything you get something like:

    
    
        square
            number: 4
    

which is just ridiculous. I kind of like Python's way of doing it -- making
them optional.

One thing's for certain -- Javascript frameworks need to develop some kind of
consistency. Sometimes you pass in parameters, and sometimes you pass in a
configuration object. This inconsistency makes it difficult, and it's too hard
to remember which calls take parameters and which take a map.

~~~
masklinn
> It would almost be easier to have everything take a map

Smalltalk and Self have demonstrated that it is, indeed, rather easy. And at
this point you can just remove the separation between "keyword arguments" and
"method name", they are one and the same.

> But if you enforce this for everything you get something like:

Well you can still have operators:

    
    
        4**2
    

or you can use a message to numbers:

    
    
        4 raisedTo: 2
    

even a unary one specifically for this operation:

    
    
        4 square
    

or you can have `square` be a message to some sort of math namespaces:

    
    
        Math square: 4

~~~
masklinn
And to go further, the network example you show (from jQuery) you could
express as:

    
    
        Request to: url withMethod: method onSuccess: success onError: error
    

with various overloads for optional component (the minimally complete
expression being `Request to: url`)

but various Smalltalk distributions & libraries have various ways to do this
(usually synchronous so it's not a precise mapping). Squeak's WebClient[0]
would be something like that:

    
    
        body := (WebClient httpGet: url) content.
    

[0] <http://www.squeaksource.com/WebClient/>

------
TamDenholm
Am i missing something or does the following code not achieve the same thing?

    
    
      // define
      function blah($arr){
          extract($arr);
          // use vars here
      }
      
      // call
      blah(['foo' => 'bar', 'one' => 'two']);

~~~
maxpert
You cant ask your users (if you are designing framework) to write such a mess.
Take an mvc framework for example where named url segments take place in
variables automatically.

~~~
ericingram
The OP solution looked messier to me honestly. We already use the pattern
above in JavaScript quite successfully. I'd rather see the above
implementation with a simple validator in place of extract().

~~~
dexen
Agreed on the `messier' part.

How's extract($arr, EXTR_IF_EXISTS) not validating enough?

------
mistercow
I've always thought that named parameters, while useful as a pattern, were not
entirely worthy of first class status. You can easily get the same
functionality with a single associative array config parameter. That also has
the additional benefit that the user of a function can reuse the config array,
tweaking individual settings between multiple function calls. All in all, the
amount of boilerplate you save by making named parameters first class is tiny
(unless, of course, your language has some kind of preposterously verbose
associative array constructor syntax, like PHP does).

~~~
masklinn
> You can easily get the same functionality with a single associative array
> config parameter.

Not really, you lose most of the validation and documentation, you get 2
levels of parameters (first-class positionals and second-class keywords), you
may not correctly detect or handle redundant provisions, defaults may or may
not work the same way (and correctly), and it's not possible to provide
through keywords a parameter the function's implementer has defined as
positional, even if that's clearer for the callsite.

It works-ish, but it is and remains a hack and a pale shadow of first-class
keyword parameters.

On the other hand, I can get behind the inverse: keyword-only parameters and
positionals by abusing arrays (à la Smalltalk, Self or Objective-C), in my
experience that significantly increases the code's readability and
flexibility. Though it hardly plays nicely with partial application.

> That also has the additional benefit that the user of a function can reuse
> the config array

parameter packing & unpacking takes care of that, it's not an advantage of "a
single associative array".

> the amount of boilerplate you save by making named parameters first class is
> tiny

To get the same functionality as e.g. Python's kwargs, we're probably talking
about half a dozen lines. In each function. That's not tiny.

~~~
wdewind
What? The benefit is not saved lines, it's ease of expressing explicitness
(ie: inline with the function call instead of throw assigning to variables
above it). Please show an example of how this is saving lines in a way that's
not comprable to simply doing multiple assigns on one line (ie: destroying
readability).

~~~
masklinn
> What? The benefit is not saved lines

Not sure what you're talking about. When somebody talks about "boilerplate",
it's very much about the number of (setup/redundant) expressions/tokens having
to be used to do something.

> Please show an example of how this is saving lines in a way that's not
> comprable to simply doing multiple assigns on one line (ie: destroying
> readability).

I would suggest actually reading my comment, that may give you a hint as to
what I'm comparing and let you understand on your own how different it is.

------
program
WordPress has a similar approach. The wp_parse_args function which accept an
array or a URL-like string. You can also pass default values (and extract()
them if you want.)

<http://codex.wordpress.org/Function_Reference/wp_parse_args>

You can pass the arguments as an array or as a URL-like ampersand separed
string.

~~~
mildweed
Wordpress should upgrade wp_parse_args to use this Gist.

------
FuzzyDunlop
The nice thing about named parameters in Python is that they're optional, and
aren't all or nothing.

From what I can tell, with this (and other similar hacks I've seen), you can
either provide no named parameters, as usual, or you have to name _every_
argument passed, in an array.

In such a case, I fail to see how implementing this can do anything but
_increase_ code complexity.

~~~
melvinmt
The example explicitly shows that optional parameters are not required:

    
    
       if (!$p->isOptional() and !isset($arr[$p->name])) throw new MissingArgumentException

------
ary
Or use Python?

~~~
notJim
Seriously. Implementing your own language features like this is a MUCH MUCH
bigger kludge than just using your language as-designed. Code like this is so
much harder to reason about and read, and so much more complicated.

If you really feel you can't program effectively in a language that lacks
keyword arguments, then for christ's sake, use a language with keyword
arguments.

------
wdewind
This doesn't actually save anytime or space, and just adds a confusing layer.
If you have to explicitly define a map of the name of the argument to the
value of it, it's not significantly shorter than just assigning the value to
the name of a variable and passing that in, ie:

$some_user_flag = true;

$some_other_flag = false;

$user->someFunction($some_user_flag, $some_other_flag);

vs. (assuming $user->someFunction is now your already defined/returned
function because this has been abstracted away in your stack somehow):

$user->someFunction(array(

    
    
        'some_user_flag' => true, 
    
        'some_other_flag' => false)
    

);

------
dexen
I'm often using compact()/extract() in similar, but not necessarily identical
pattern. For example:

    
    
      $foo = get_some_value();
      $bar = get_other_value();
      my_function(compact('foo', 'bar'));
    
      function my_function($args) {
          # optionally provide default values :-)
        $foo = default_value;
        $bar = default_value;
        extract($args, EXTR_IF_EXISTS); # the EXTR_IF_EXISTS is optional, for when we want to enforce sanity check
          /* function code goes here */
      }
    

(edits: clarifications)

~~~
notJim
Why? This is a horrible idea. It makes your code so much harder to read or
reason about, because it's impossible to tell what variables will be passed in
without looking at every single callsite.

~~~
dexen
That's not how the code works; I can assure you after using it for some time.
The client code (the callee) is in control of variables and lists explicitly
what will be provided, either as default or as an actual (keyword) argument.

When using EXTR_IF_EXISTS and list of default values, you know exactly what
variables you will get -- either passed as argument, or by default, by reading
the callee.

When _not_ using EXTR_IF_EXISTS and you want to extract only known-good
variables from untrusted input, array_intersect_key() helps.

The idiom may seem strange at first, but once you get used to it, you read it
naturally. That's the thing with idioms, after all. Point in case, our new
hire got up to speed very quickly.

\----

EDIT: in some cases I just skip the extract()ing and simply access
$args['field_name']. It's safe as PHP will raise error, stop execution and
drop to error handler if some field was not provided by mistake -- or
malicious user action. And any superfluous fields remain unaccessed, safe
again.

------
zippie
Performance note - having call_* functions in your code guarantees that your
work will not opcode cache friendly - WP is guilty of this (in addition to
their include/require spaghetti).

------
shepik
I'd suggest adding "take this regular function and return function callable
with array" function: <https://gist.github.com/3029279>

(also, this variant is better because you can mitigate performance losses by
moving all reflection operations out of lambda function to its parent,
make_named_array_function)

~~~
maxpert
Added

------
superasn
Cool, but if you're using it in a production code do make sure to link this
blog post as a comment. You don't want some poor developer who takes over your
project scratching his head.

P.S. Sometimes that poor developer can you be too ;) Don't know how many times
what seemed to be a _great_ idea at a moment to me, leads to the biggest wtf
after a month.

------
MattBearman
You can do the following in PHP:

    
    
      some_function($param='hello', $somthingelse=3);
    

It's not quite as good as the method in this post, as you still have to
specify params in the correct order, but it means at a glance it's easier to
remember what each parameter is. In fach I do this a lot for that very reason.

~~~
function_seven
That doesn't seem "right" to me, though. What if you have a variable in your
calling scope that conflicts with a parameter in your function?

------
jstsch
This will kill your performance... function calls are slow, but calling them
via call_user_func is crazy slow.

~~~
chrisohara
It's pretty negligible in the scheme of things. I was abusing PHP reflection a
while back to add decorator support (<https://github.com/chriso/Request>) and
used this pattern to reduce the cost:

    
    
        switch (count($args)) {
            case 0: $method(); break;
            case 1: $method($args[0]); break;
            case 2: $method($args[0], $args[1]); break;
            //etc
            default: call_user_func_array($method, $args); break;
        }

------
antihero
Why not something like?

    
    
        function myfunc($kwargs) {
            extract($kwargs);
        }
    

And then just call it with an array. Sure, it's ugly, but that's the price of
using PHP.

------
jaequery
i'd advise the OP to pass in an array. and look into an API-inspired pattern
which organizes code and above all, proper type-chcking and error handling.

for instance:

$result = App:api('/do/something', array(name=>'john', age=>10, etc));

class Do extends Api { function something($params = array('name'=>'',
age=>'')){ ... } }

------
ranza
Besides the ugly syntax look... Awesome feature!

------
jessedhillon
The result is some very sad looking code.

~~~
maxpert
Sad in what sense?

~~~
beezee
Sad is definitely overkill here, especially for such a short snippet, but
personally I prefer avoiding nested conditionals and else statements in
general. Here's a fork that keeps conditional clauses to one line, and I
personally find much more readable - <https://gist.github.com/3029246>

(disclaimer- not tested at all)

~~~
maxpert
Thanks for forking and keep improving, I wish PHP guys do it at a native level
too.

