Любой способ указать необязательные значения параметров в PHP?
предположим, у меня есть функция PHP foo:
function foo($firstName = 'john', $lastName = 'doe') {
echo $firstName . " " . $lastName;
}
// foo(); --> john doe
есть ли способ указать только второй необязательный параметр?
пример:
foo($lastName='smith'); // output: john smith
12 ответов
PHP не поддерживает именованные параметры для функций как таковых. Тем не менее, есть несколько способов обойти это:
- использовать массив в качестве единственного аргумента для функции. Затем вы можете извлечь значения из массива. Это позволяет использовать именованные аргументы в массив.
- Если вы хотите разрешить необязательное количество аргументов в зависимости от контекста, вы можете использовать func_num_args и func_get_args вместо указания допустимых параметров в определении функции. Затем, исходя из количества аргументов, длины строк и т. д. Вы можете определить, что делать.
- передайте значение null любому аргументу, который вы не хотите указывать. Не очень-то получается, но работает.
- Если вы работаете в контексте объекта, то вы можете использовать метод magic __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');
есть несколько реализаций стиля "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
в этом примере) и предотвращает создание любых переменных, которые не имеют значения по умолчанию. Это значит, что никто не может случайно перезаписать другие параметры или другие переменные внутри функции.
аргументы должны быть переданы в положение, вы не можете пропустить параметр как таковой; вам нужно будет указать значение параметра по умолчанию, чтобы пропустить его. Возможно, это разрушает цель того, чего вы пытаетесь достичь.
не переписывая свою функцию, чтобы принимать параметры по-разному, вот способ обойти это:
$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']);
Я хотел бы, чтобы это решение было включено, когда я начал использовать 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'));
результаты:
собака стояла на осел!--4-->
кот сел на осла
на циновке стояла собака
Если это используется очень часто, просто определите новую специализированную функцию:
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, потому что вы можете сделать, просто фу( имя => 'Джон' );
нет, но вы можете использовать массив:
function foo ($nameArray) {
// Work out which values are missing?
echo $nameArray['firstName'] . " " . $nameArray['lastName'];
}
foo(array('lastName'=>'smith'));