Руби-подобная реализация аргументов массива в PHP

В основном я программирую на PHP, а на Ruby иногда мне нужен способ реализовать эти «хэш-аргументы» в мои функции PHP (например, помощник выбора HTML)

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

Проблема в PHP заключается в том, что мне пришлось бы определять порядок аргументов для реализации многих возможных атрибутов.

Я думал просто определить 1 строковый аргумент и использовать json_decode(), чтобы я мог передавать такие аргументы:

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

определение будет следующим:

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

Знаете ли вы более разумный способ сделать это... или вы думаете, что попытки сделать это в PHP действительно имеют какой-то смысл?

Отредактировано для добавления: я ищу «альтернативную» альтернативу, чтобы просто передать массив знаков в качестве аргумента, например function(array(...))


person Guillermo    schedule 15.05.2009    source источник
comment
Реальной альтернативы нет. Что не так с методом массива? Вот как это делается в PHP. Не пытайтесь бороться с языком, чтобы сделать из него то, чем он не является.   -  person Paolo Bergantino    schedule 15.05.2009


Ответы (6)


PHP определенно не хватает сахара в этом аспекте. Я также много работаю с Python, и мне очень не хватает именованных аргументов при использовании PHP. Однако с PHP всякий раз, когда у меня есть функция, которая должна принимать множество параметров, я просто принимаю один или два обязательных/важных аргумента и массив для остальных:

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

}

Именно так библиотеки, такие как CodeIgniter и CakePHP, обрабатывают один и тот же сценарий <select>.

Лично использование JSON в этой ситуации не приносит реальной пользы, когда ассоциативные массивы PHP настолько мощны. Просто придерживайтесь того, что дает вам язык, и это способ сделать это с помощью PHP.

person Paolo Bergantino    schedule 15.05.2009

Почему бы вместо этого не передать массив?

draw_select(array(
  'name'=> 'id', 
  'onclick'=> 'alert(this.value)'
));
person Frank Farmer    schedule 15.05.2009
comment
я думал об этом, но это не так элегантно, как в Ruby, - person Guillermo; 15.05.2009
comment
Это более элегантно, чем передача строки и ее декодирование JSON :) - person Frank Farmer; 16.05.2009
comment
Этот подход к передаче массива - это именно то, что делает ваш желаемый метод Ruby, если вы посмотрите на реализацию draw_select, это, вероятно, что-то вроде: def draw_select(opts = {}), поэтому он просто принимает хэш. РНР-эквивалент передачи массива — это именно так! - это эквивалент! Я не вижу, как вы можете получить больше эквивалента, чем это. - person Cody Caughlan; 16.05.2009
comment
В качестве дополнения, поскольку Ruby позволяет вам пропускать синтаксические символы, такие как открывающая скобка и фигурная скобка, кажется, что аргументы являются позиционными, но на самом деле это не так. Это всего лишь хеш - person Cody Caughlan; 16.05.2009

Невозможно1 сделать это в любой версии PHP вплоть до PHP 5.3 включительно.

PHP не поддерживает именованные параметры и/или селекторы стиля smalltalk/objective-c/ruby. PHP также не предлагает способа переопределить эту часть языка. Если вы хотите это в PHP, вам не повезло. PHP никогда не был лучшим языком для так называемого «метапрограммирования».

Как уже упоминалось, лучше всего с PHP использовать массив с парами ключ/значение в сочетании с экстрактом.

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

function myFunction($params){
    extract($params);
    echo $param2;
}   
  1. Вероятно, вы могли бы написать расширение на C/C++, чтобы расширить PHP с помощью этой возможности, но вы были бы мазохистом. :)
person Alan Storm    schedule 16.05.2009
comment
+1 за упоминание extract()... что часто упускают из виду - person dreftymac; 13.07.2009

Поскольку все варианты здесь включают вызов array, и это, кажется, "PHPish" способ ведения дел, я добавлю, что, если вы делаете это все время, что, возможно, имеет смысл иметь функцию z() (я я просто думаю о том, что $() в jQuery) с псевдонимом array(). Помимо длины массива имен, я не вижу, чтобы версия Ruby была более элегантной. Символов меньше, но мне несколько не нравится то, что в этом примере кода нельзя сразу отличить параметр функции от пары ключ/значение.

person Oliver N.    schedule 15.05.2009

Решение состоит в использовании переменных аргументов.

Я иногда использую это с языками, которые изначально не поддерживают ассоциативные массивы.

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! ');

Хотя стыдно использовать это для PHP, поскольку он изначально поддерживает ассоциативные массивы...

person Vincent Robert    schedule 15.05.2009

Вы можете использовать функцию «func_get_args()» и просто использовать каждый первый параметр как имя переменной и каждый второй как значение. Вероятно, это так же близко, как вы собираетесь добраться до рубинового пути (я искал целую вечность, как это сделать, я точно понимаю, что вы имеете в виду под элегантным решением ruby ​​для массивов). Надеюсь, в будущем PHP откроется для перепрограммирования при выполнении, как это может быть в случае с ruby ​​(не знаю, как это на самом деле называется, но это то, что делает ruby ​​и ruby ​​on rails такими блестящими).

person Community    schedule 18.07.2009