Любой способ указать необязательные значения параметров в PHP? - PullRequest
20 голосов
/ 27 марта 2009

Допустим, у меня есть PHP-функция foo:

function foo($firstName = 'john', $lastName = 'doe') {
    echo $firstName . " " . $lastName;
}
// foo(); --> john doe

Можно ли указать только второй необязательный параметр?

Пример:

foo($lastName='smith'); // output: john smith

Ответы [ 12 ]

32 голосов
/ 27 марта 2009

PHP не поддерживает именованные параметры для функций как таковых. Однако есть несколько способов обойти это:

  1. Использовать массив в качестве единственного аргумента для функции. Затем вы можете извлечь значения из массива. Это позволяет использовать именованные аргументы в массиве.
  2. Если вы хотите разрешить необязательное количество аргументов в зависимости от контекста, вы можете использовать func_num_args и func_get_args вместо указания допустимых параметров в определении функции. Затем, основываясь на количестве аргументов, длине строки и т. Д., Вы можете определить, что делать.
  3. Передайте нулевое значение любому аргументу, который вы не хотите указывать. На самом деле не обойтись, но это работает.
  4. Если вы работаете в объектном контексте, то вы можете использовать магический метод __call () для обработки этих типов запросов, чтобы вы могли перенаправлять их в закрытые методы на основе переданных аргументов.
22 голосов
/ 27 марта 2009

Вариант метода массива, позволяющий упростить установку значений по умолчанию:

function foo($arguments) {
  $defaults = array(
    'firstName' => 'john',
    'lastName' => 'doe',
  );

  $arguments = array_merge($defaults, $arguments);

  echo $arguments['firstName'] . ' ' . $arguments['lastName'];
}

Использование:

foo(array('lastName' => 'smith')); // output: john smith
9 голосов
/ 27 марта 2009

Вы можете немного изменить свой код:

function foo($firstName = NULL, $lastName = NULL)
{
    if (is_null($firstName))
    {
        $firstName = 'john';
    }
    if (is_null($lastName ))
    {
        $lastName = 'doe';
    }

    echo $firstName . " " . $lastName;
}

foo(); // john doe
foo('bill'); // bill doe
foo(NULL,'smith'); // john smith
foo('bill','smith'); // bill smith
6 голосов
/ 27 марта 2009

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

function foo(array $params = array()) {
    echo $params['firstName'] . " " . $params['lastName'];
}

foo(array('lastName'=>'smith'));

Конечно, в этом решении нет подтверждения того, что поля массива хэшей присутствуют или пишутся правильно. Все зависит от вас, чтобы проверить.

3 голосов
/ 27 марта 2009

Как вы хотите: нет.

Вы можете использовать специальную метку, например, NULL, чтобы отметить, что значение не указано:

function foo($firstName, $lastName = 'doe') {
    if (is_null($firstName))
        $firstName = 'john';
    echo $firstName . " " . $lastName;
}

foo(null, 'smith');
3 голосов
/ 27 марта 2009

Нет. Обычный способ сделать это с помощью некоторой эвристики, чтобы определить, какой параметр подразумевался, например, длина строки, тип ввода и т. Д.

Вообще говоря, вы бы написали функцию, принимающую параметры в порядке от наиболее требуемого до наименее необходимого.

1 голос
/ 26 августа 2015

Аргументы необходимо передать , чтобы по позиции нельзя пропустить параметр как таковой; вам нужно будет указать значение параметра по умолчанию, чтобы пропустить его. Возможно, это побеждает цель того, чего вы пытаетесь достичь.

Не переписывая вашу функцию, чтобы принимать параметры по-другому, вот способ во время вызова, чтобы обойти это:

$func = 'foo';
$args = ['lastName' => 'Smith'];

$ref = new ReflectionFunction($func);
$ref->invokeArgs(array_map(function (ReflectionParameter $param) use ($args) {
    if (array_key_exists($param->getName(), $args)) {
        return $args[$param->getName()];
    }
    if ($param->isOptional()) {
        return $param->getDefaultValue();
    }
    throw new InvalidArgumentException("{$param->getName()} is not optional");
}, $ref->getParameters()));

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

call_func_with_args_by_name('foo', ['lastName' => 'Smith']);
1 голос
/ 19 августа 2015

Хотелось бы, чтобы это решение было на SO, когда я начал использовать PHP 2,5 года назад. Он прекрасно работает в примерах, которые я создал, и я не понимаю, почему он не должен быть полностью расширяемым. Он предлагает следующие преимущества по сравнению с предложенными ранее:

(i) весь доступ к параметрам внутри функции осуществляется по именованным переменным, как если бы параметры были полностью объявлены, а не требует доступа к массиву

(ii) очень быстро и легко адаптировать существующие функции

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

Метод

Определите вашу функцию с ее обязательными параметрами и необязательным массивом

Объявите необязательные параметры в качестве локальных переменных

Суть: заменить предварительно объявленное значение по умолчанию любых необязательных параметров, используя те, которые вы передали через массив.

extract(array_merge($arrDefaults, array_intersect_key($arrOptionalParams, $arrDefaults)));

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

Например,

function test_params($a, $b, $arrOptionalParams = array()) {

$arrDefaults = array('c' => 'sat',

                     'd' => 'mat');

extract(array_merge($arrDefaults, array_intersect_key($arrOptionalParams, $arrDefaults)));

echo "$a $b $c on the $d";

}

и затем назовите это так

test_params('The', 'dog', array('c' => 'stood', 'd' => 'donkey'));
test_params('The', 'cat', array('d' => 'donkey'));
test_params('A', 'dog', array('c' => 'stood'));

Результаты:

собака стояла на осле

Кот сел на осла

На коврике стояла собака

1 голос
/ 11 апреля 2014

Есть несколько реализаций стиля 'options', упомянутых здесь. Пока что никто не является пуленепробиваемым, если вы планируете использовать их в качестве стандарта. Попробуйте этот шаблон:

function some_func($required_parameter, &$optional_reference_parameter = null, $options = null) {
    $options_default = array(
        'foo' => null,
    );
    extract($options ? array_intersect_key($options, $options_default) + $options_default : $options_default);
    unset($options, $options_default);

    //do stuff like
    if ($foo !== null) {
        bar();
    }
}

Это дает вам локальные переменные функции (просто $foo в этом примере) и предотвращает создание любых переменных, которые не имеют значений по умолчанию. Это так, что никто не может случайно перезаписать другие параметры или другие переменные внутри функции.

0 голосов
/ 15 ноября 2016

Если это используется очень часто, просто определите новую специализированную функцию:

function person($firstName = 'john', $lastName = 'doe') {
    return $firstName . " " . $lastName;
}

function usualFirtNamedPerson($lastName = 'doe') {
    return person('john', $lastName);
}

print(usualFirtNamedPerson('smith')); --> john smith

Обратите внимание, что вы также можете изменить значение по умолчанию $ lastname в процессе, если хотите.

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

$firstName = 'Zeno';
$lastName = 'of Elea';
print(person($firstName, $lastName));
print(person(/* $firstName = */ 'Bertrand', /* $lastName = */ 'Russel'));

Хорошо, это не так коротко и элегантно, как person($lastName='Lennon'), но, похоже, в PHP этого не может быть. И это не самый сексуальный способ его кодирования, с трюком супер метапрограммирования или чем-то еще, но с каким решением вы бы предпочли столкнуться в процессе обслуживания?

...