Предположим, у меня есть функция PHP foo:
function foo($firstName = 'john', $lastName = 'doe') { echo $firstName . " " . $lastName; } // foo(); --> john doe
Есть ли способ указать только второй необязательный параметр?
Пример:
foo($lastName='smith'); // output: john smith
PHP не поддерживает именованные параметры для самих функций. Однако есть некоторые способы обойти это:
Вариант метода массива, который позволяет упростить установку значений по умолчанию:
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');
Существует несколько реализаций стиля опций, упомянутых здесь. Пока что они не являются пуленепробиваемыми, если вы планируете использовать их как стандартные. Попробуйте этот шаблон:
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']);
Я хочу, чтобы это решение было на 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'));
Результаты:
Собака стояла на ослике
Кошка сидела на ослике
На коврике стояла собака
Если это используется очень часто, просто определите новую специализированную функцию:
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'));