Должны ли мои функции PHP принимать массив аргументов или я должен явно запрашивать аргументы?

В веб-приложении PHP, над которым я работаю, я вижу функции, определенные двумя возможными способами.

Подход 1:

function myfunc($arg1, $arg2, $arg3)

Подход 2:

// where $array_params has the structure array('arg1'=>$val1, 'arg2'=>$val2, 'arg3'=>$val3)
function myfunc($array_params)

Когда я должен использовать один подход над другим? Похоже, что если системные требования продолжают меняться, и поэтому количество аргументов для myfunc продолжает меняться, подход 1 может потребовать много обслуживания.

Ответ 1

Если система меняется так часто, что использование индексированного массива - лучшее решение, я бы сказал, что это меньше всего беспокоит вас.: -)

В общих функциях/методах не должно приниматься слишком много аргументов (максимум 5 плюс или минус 2), и я бы сказал, что вы должны придерживаться использования имени (и идеально тип намечен) аргументы. (Индексированный массив аргументов действительно имеет смысл, если имеется большое количество дополнительных данных - хорошим примером является информация о конфигурации.)

Как говорит @Pekka, передача массива аргументов также может быть больно документировать, а потому для других людей/себя в "n" месяцах поддерживать.

Update-Ette...

Кстати, упомянутая выше книга Code Complete рассматривает такие проблемы довольно подробно - это отличный тома, который я бы очень рекомендую.

Ответ 2

Использование массива params (суррогат для так называемых аргументов "на других языках" ) отлично - мне нравится его использовать самостоятельно, но он имеет довольно большой недостаток: аргументы не документируются с использованием стандартной записи phpDoc, которая и, следовательно, ваша IDE не сможет дать вам подсказки при вводе имени функции или метода.

Ответ 3

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

Примером может быть, если я хочу настроить контейнер для видео на моей веб-странице:

function buildVideoPlayer($file, $options = array())
{
  $defaults = array(
    'showAds' => true,
    'allowFullScreen' = true,
    'showPlaybar' = true
  );

 $config = array_merge($defaults, $options);

 if ($config['showAds']) { .. }
}

$this->buildVideoPlayer($url, array('showAds' => false));

Обратите внимание, что начальное значение $options является пустым массивом, поэтому предоставление его вообще необязательно.

Кроме того, с помощью этого метода мы знаем, что $options всегда будет массивом, и мы знаем, что эти ключи имеют значения по умолчанию, поэтому нам не нужно постоянно проверять is_array() или isset() при ссылке на аргумент.

Ответ 4

Есть плюсы и минусы по каждому пути.

  • Если это простая функция, которая вряд ли изменится и будет иметь только несколько аргументов, я бы указал их явно.

  • Если функция имеет большое количество аргументов или, скорее всего, многое изменит в будущем, я передам массив аргументов с ключами и использую это. Это также становится полезным, если у вас есть функция, в которой вам нужно просто часто передавать некоторые аргументы.

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

  • Введите
  • Значение
  • класс
  • ID
  • стиль
  • Параметры
  • is_required

и мне может потребоваться только несколько из них. например, если поле type = text, мне не нужны параметры. Мне может не всегда понадобиться класс или значение по умолчанию. Таким образом, легче передать несколько комбинаций аргументов, не имея сигнатуры функции с аргументами тонны и все время пропуская нуль. Кроме того, когда HTML 5 становится стандартным много лет спустя, я могу добавить дополнительные возможные аргументы, например, включить или выключить автозаполнение.

Ответ 5

с первым подходом вы заставляете пользователей вашей функции предоставлять все необходимые параметры. во-вторых, вы не можете быть уверены, что у вас есть все, что вам нужно. Я бы предпочел первый подход.

Ответ 6

Если параметры, которые вы передаете, могут быть сгруппированы логически, вы можете подумать об использовании объекта параметра (Refactoring, Martin Fowler, p295), таким образом, если вам нужно добавить дополнительные параметры, вы можете просто добавить дополнительные поля в свои класс параметра, и он не нарушит существующие методы.

Ответ 7

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

      class user{
           public $id;
           public $name;
           public $address;
           ...
      }

и вызовите:

      $user = new user();
      $user->id = ...
      ...

      callFunctions($user);

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