Я часто вижу эту идиому, читая php код:
public function __construct($config)
{
if (array_key_exists('options', $config)) {
...
}
if (array_key_exists('driver_options', $config)) {
...
}
}
Здесь я - беспокойство со способом, которым используется параметр. Если бы я был в шепелявости, то я сделал бы:
(defun ct (&key options driver_options)
(do-something-with-option-and-driver_option))
Но так как я нахожусь в PHP, у меня был бы конструктор, которые берут список параметра и позволяют им быть пустыми, если там не требуют.
Таким образом, что делает Вас, парни думают о наличии массива как параметр в другом делать некоторый initialization-whatever?
В другом для ответа необходимо взять в учетной записи точку зрения пользователя функции и разработчика API.
Лично мне не нравится эта идиома. Вместо этого я предпочитаю иметь длинный список параметров, если это необходимо.
Проблема в том, что я не могу узнать элементы, которые массив не может принять, глядя на сигнатуру функции. Вдобавок к этому, реализации почти никогда не проверяют, есть ли какой-либо ключ, который не распознан, поэтому, если я неправильно введу ключ массива, я не получу предупреждения.
Лучшей альтернативой была бы передача объекта конфигурации. По крайней мере, там IDE может предоставить мне подсказки по доступным объектам конфигурации, а вычисленные значения по умолчанию для отсутствующих параметров могут быть перемещены из конструктора, который вы показываете геттерам в объекте конфигурации. Очевидная альтернатива - предоставить установщики для нескольких опций конфигурации; хотя это не помогает для требуемых для каждого, не может быть предоставлено значение по умолчанию.
Мне очень нравится шаблон проектирования «массивов опций». Если бы 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
}
}
}
Одна вещь. Если вы это сделаете, ПОЖАЛУЙСТА, задокументируйте требуемые параметры. Это значительно облегчит жизнь тем, кто последует за вами.
Я нахожу использование массивов в качестве параметров полезным, когда есть много необязательных параметров. Обычно я использую array_merge, чтобы объединить переданный массив с массивом "defaults". Проверка не требуется. Если у вас есть обязательные параметры, вы можете использовать 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);
}