Передача массива для установки переменной - PullRequest
1 голос
/ 07 июня 2010

Я часто вижу эту идиому при чтении php-кода:

public function __construct($config)
{
    if (array_key_exists('options', $config)) {
       ...
    }
    if (array_key_exists('driver_options', $config)) {
        ...
    }
}

Здесь я обеспокоен тем, как используется параметр.Если бы я был в lisp, я бы сделал:

(defun ct (&key options driver_options) 
       (do-something-with-option-and-driver_option))

Но так как я нахожусь в PHP, я бы предпочел иметь конструктор, который принимает список параметров и позволяет им быть нулевыми, если нет необходимости.

Так что вы, ребята, думаете о том, чтобы иметь массив в качестве параметра в другом для выполнения некоторой инициализации или чего-то еще?

Другими словами, чтобы ответить, вы должны принять во внимание точку зрения пользователяфункция и конструктор API.

Ответы [ 3 ]

1 голос
/ 07 июня 2010

Мне очень нравится шаблон проектирования "массивов опций".Если бы PHP поддерживал расширение аргументов Python, я бы согласился с длинным списком параметров.Но я просто нахожу foo(1, 2, 'something', true, 23, array(4), $bar); ДЕЙСТВИТЕЛЬНО нечитаемым.Обычно я буду использовать массивы, когда нужно установить более 3 или 4 параметров ...

Я бы посоветовал «очистить» конструктор, создав защищенный метод для доступа к конфигурационным переменным.(предпочтительно в базовом классе):

abstract class Configurable {
    protected $options = array();
    protected $requiredOptions = array();

    public function __construct(array $options = array()) {
        $this->options = $options;
        foreach ($this->requiredOptions as $option) {
            if (!isset($this->options[$option])) {
                throw new InvalidArgumentException('Required argument [$'.$option.'] was not set');
            }
        }
    }

    protected function _getOption($key, $default = null) {
        return isset($this->options[$key]) ? $this->options[$key] : $default;
    }
}

Затем в вашем классе вы можете перегрузить массив requireOptions, чтобы определить вещи, которые нужно установить

class Foo extends Configurable {
    protected $requiredOptions = array(
        'db',
        'foo',
    );

    public function __construct(array $options = array()) {
        parent::__construct($options);
        if ($this->_getOption('bar', false)) {
            //Do Something
        }
    }
}

Одна вещь. Если вы сделаете это, ПОЖАЛУЙСТА, документируйте необходимые параметры.Тем, кто последует за вами, станет намного легче.

1 голос
/ 07 июня 2010

Лично мне не нравится эта идиома. Вместо этого я предпочитаю иметь длинный список параметров.

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

Лучшей альтернативой будет передача объекта конфигурации. По крайней мере, в этой среде IDE может предоставить подсказки о доступных объектах конфигурации, а вычисленные значения по умолчанию для отсутствующих параметров можно перенести из отображаемого конструктора в методы получения объекта конфигурации. Очевидная альтернатива - предоставить установщики для нескольких параметров конфигурации; хотя это не помогает для требуемых для каждого, по умолчанию не может быть предоставлено.

0 голосов
/ 07 июня 2010

Я считаю использование массивов в качестве параметров полезным, когда есть много дополнительных параметров.Обычно я буду использовать array_merge для объединения переданного массива с массивом «по умолчанию».Проверка не требуется.Если у вас есть обязательные параметры, вы можете использовать array_diff_key, чтобы определить, отсутствуют ли какие-либо обязательные параметры.

function params($p_array) {
    static $default_vals = array('p1'=>1, 'p2'=>null, 'p3'=>'xyz');
    static $rqd_params = array('p1'=>null, 'p3'=>null);
    // check for missing required params
    $missing_params = array_diff_key($rqd_params, $p_array);
    if ( count($missing_params)>0 ) {
       //return an error (i.e. missing fields)
       return array_keys($missing_params);
    }
    // Merge passed params and override defaults
    $p_array = array_merge($default_vals, $p_array);
}
...