-->

Ruby-like array arguments implementation in PHP

2019-08-02 04:10发布

问题:

I program in PHP mostrly and Ruby sometimes I happen to be in need of a way to implements those "hash arguments" into my PHP funcions (Like, say, an HTML select helper)

draw_select :name => :id, :onclick => 'alert(this.value)'

The problem in PHP is that I would have to define an argument order to implement many possible attributes.

I have been thinking of just define 1 string argument and use json_decode() so i can pass arguments like this:

draw_select("'name': 'id', 'onclick': 'alert(this.value)' ")

the definition would be as follows:

function draw_select($string) {
// use json_decode here and pass them as variables
}

Do you know a smarter way to do this.. or you think that triying to to this in PHP does actually makes any sense at all?

Edited to add: I'm looking for a 'alternative' alternative to just pass a signle array as an argument like function(array(...))

回答1:

PHP definitely is lacking some sugar in this aspect. I do a lot of Python also and I dearly miss named arguments when using PHP. With PHP, however, whenever I have a function that will need to accept a multitude of options I simply accept one or two required/important arguments, and an array for the rest:

function draw_select($name, $options = array(), $html_options = array()) {

}

This is the way libraries like CodeIgniter and CakePHP handle the same <select> scenario.

Personally, using JSON in this situation brings no real benefit when PHP's associative arrays are so powerful. Just stick to what the language gives you, and this is the way to do it with PHP.



回答2:

Why not pass an array instead?

draw_select(array(
  'name'=> 'id', 
  'onclick'=> 'alert(this.value)'
));


回答3:

There's no1 way to do this in any version of PHP up to and including PHP 5.3.

PHP doesn't have support for named parameters and/or smalltalk/objective-c/ruby style selectors. PHP doesn't offer a way to redefine this part of the language either. If you want this in PHP you're out of luck. PHP has never been the best language choice for so-called "meta-programming".

As others have mentioned, your best bet with PHP is to use an array with key/value pairs in combination with extract.

myFunction(array(
    'theThing'=>0,
    'param2'=>'another value',
));

function myFunction($params){
    extract($params);
    echo $param2;
}   
  1. You could probably write an extension on C/C++ to extend PHP with this ability, but you'd be a masochist. :)


回答4:

Since all the options here involve calling array, and it seems to be the "PHPish" way of doing things, I'll throw in that if you're doing this all the time that maybe it makes sense to have a function z() (I'm just thinking along the lines of $() in jQuery) that aliases to array(). Besides the length of the name array, I don't see how the Ruby version is any more elegant. There are less characters, but I somewhat dislike that you can't immediately tell the difference between a function parameter and a key/value pair in that example code.



回答5:

A solution is to use variable arguments.

I sometimes use this with languages that don't support associative arrays natively.

function AssociativeArrayFromFlatArray($args)
{
    $nbArgs = count($args);
    if( $nbArgs % 2 != 0 )
    {
        die('This function must have an even number of arguments');
    }

    $ret = array();
    for( $i = 0; $i < $nbArgs; $i += 2 )
    {
        $key = $args[$i];
        $value = $args[$i + 1];
        $ret[$key] = $value;
    }
    return $ret;
}

function DoSomething(/*...*/)
{
    $args = AssociativeArrayFromFlatArray(func_get_args());

    if( $args['action'] == 'greet' )
    {
        $count = $args['count'] or 1;
        for( $i = 0; $i < $count; $i += 1 )
        {
            echo $args['text'];
        }
    }
}

DoSomething('action', 'greet', 'count', 10, 'text', 'Hello World! ');

Though this is a shame to use this for PHP since it natively supports associative arrays...



回答6:

You could use the 'func_get_args()' function and just use every first parameter as a var name and every second as the value. It's probably as close as your going to get to the ruby way (I've been looking for ages on a way to do it, I understand exactly what you mean about ruby's elegant solution to arrays). Hopefully in the future PHP opens it's self up to be reprogrammed on execution like ruby can be(don't know what that's actually called, but it is what makes ruby and ruby on rails so brilliant).