Любой способ указать необязательные значения параметров в PHP?
Допустим, у меня есть PHP-функция foo:
function foo($firstName = 'john', $lastName = 'doe') {
echo $firstName . " " . $lastName;
}
// foo(); --> john doe
Есть ли способ указать только второй необязательный параметр?
Пример:
foo($lastName='smith'); // output: john smith
13 ответов
PHP не поддерживает именованные параметры для функций как таковых. Однако есть несколько способов обойти это:
- Используйте массив в качестве единственного аргумента для функции. Затем вы можете извлечь значения из массива. Это позволяет использовать именованные аргументы в массиве.
- Если вы хотите разрешить необязательное количество аргументов в зависимости от контекста, вы можете использовать func_num_args и func_get_args вместо указания допустимых параметров в определении функции. Затем на основе количества аргументов, длины строк и т. Д. Вы можете определить, что делать.
- Передайте нулевое значение любому аргументу, который вы не хотите указывать. На самом деле не обойтись, но это работает.
- Если вы работаете в объектном контексте, то вы можете использовать магический метод __call() для обработки этих типов запросов, чтобы вы могли перенаправлять их в закрытые методы в зависимости от того, какие аргументы были переданы.
Разновидность метода массива, позволяющая упростить установку значений по умолчанию:
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
Вы можете немного изменить свой код:
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
Если у вас есть несколько необязательных параметров, одним из решений является передача одного параметра, который является хеш-массивом:
function foo(array $params = array()) {
echo $params['firstName'] . " " . $params['lastName'];
}
foo(array('lastName'=>'smith'));
Конечно, в этом решении нет подтверждения того, что поля массива хэшей присутствуют или пишутся правильно. Все зависит от вас, чтобы подтвердить.
Нет. Обычный способ сделать это с помощью некоторой эвристики, чтобы определить, какой параметр подразумевался, например, длина строки, тип ввода и т. Д.
Вообще говоря, вы бы написали функцию, принимающую параметры в порядке от наиболее требуемого до наименее необходимого.
Так, как вы хотите: нет.
Вы можете использовать некоторую специальную метку, например, NULL, чтобы отметить, что значение не указано:
function foo($firstName, $lastName = 'doe') {
if (is_null($firstName))
$firstName = 'john';
echo $firstName . " " . $lastName;
}
foo(null, 'smith');
PHP 8 представил именованные аргументы, поэтому теперь можно указать параметры, передаваемые функции.
до PHP 8:
htmlspecialchars($string, ENT_COMPAT | ENT_HTML401, 'UTF-8', false);
после PHP 8:
htmlspecialchars($string, double_encode: false);
Я хотел бы, чтобы это решение было на 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'));
Результаты:
Собака стояла на осле
Кот сел на осла
Собака стояла на коврике
Аргументы должны передаваться по порядку по позиции, вы не можете пропустить параметр как таковой; вам нужно будет указать значение параметра по умолчанию, чтобы пропустить его. Возможно, это побеждает цель того, чего вы пытаетесь достичь.
Не переписывая вашу функцию для принятия параметров по-другому, вот способ во время вызова обойти это:
$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']);
Есть несколько реализаций стиля '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
в этом примере) и предотвращает создание любых переменных, которые не имеют значения по умолчанию. Это так, что никто не может случайно перезаписать другие параметры или другие переменные внутри функции.
Если это используется очень часто, просто определите новую специализированную функцию:
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. И это не самый сексуальный способ его кодирования, с трюком супер метапрограммирования или чем-то еще, но с каким решением вы бы предпочли столкнуться в процессе обслуживания?
К сожалению, то, что вы пытаетесь сделать, не имеет "синтаксического сахара". Они все разные формы WTF.
Если вам нужна функция, которая принимает неопределенное количество произвольных параметров,
function foo () {
$args = func_get_args();
# $args = arguments in order
}
Сделаем трюк. Старайтесь не использовать его слишком много, потому что для Php это немного магически.
Затем вы можете при желании применять значения по умолчанию и делать странные вещи, основываясь на количестве параметров.
function foo(){
$args = func_get_args();
if( count($args) < 1 ){
return "John Smith";
}
if( count($args) < 2 ) {
return "John " .$args[0];
}
return $args[0] . " " . $args[1];
}
Кроме того, вы можете по желанию эмулировать параметры стиля Perl,
function params_collect( $arglist ){
$config = array();
for( $i = 0; $i < count($arglist); $i+=2 ){
$config[$i] = $config[$i+1];
}
return $config;
}
function param_default( $config, $param, $default ){
if( !isset( $config[$param] ) ){
$config[$param] = $default;
}
return $config;
}
function foo(){
$args = func_get_args();
$config = params_collect( $args );
$config = param_default( $config, 'firstname' , 'John' );
$config = param_default( $config, 'lastname' , 'Smith' );
return $config['firstname'] . ' ' . $config['lastname'];
}
foo( 'firstname' , 'john', 'lastname' , 'bob' );
foo( 'lastname' , 'bob', 'firstname', 'bob' );
foo( 'firstname' , 'smith');
foo( 'lastname', 'john' );
Конечно, здесь было бы проще использовать аргумент массива, но вы можете иметь выбор (даже плохие способы) что-то делать.
Следует отметить, что это лучше в Perl, потому что вы можете сделать просто foo (firstname => 'john');
Нет, но вы можете использовать массив:
function foo ($nameArray) {
// Work out which values are missing?
echo $nameArray['firstName'] . " " . $nameArray['lastName'];
}
foo(array('lastName'=>'smith'));