именованные необязательные аргументы PHP?
возможно ли в PHP 4/5 указать именованный необязательный параметр при вызове, пропуская те, которые вы не хотите указывать (например, в python) ?
что-то типа:
function foo($a,$b='', $c='') {
// whatever
}
foo("hello", $c="bar"); // we want $b as the default, but specify $c
спасибо
17 ответов
нет, это невозможно : если вы хотите передать третий параметр, вы должны передать второй. И именованные параметры также невозможны.
"Решением"было бы использовать только один параметр, массив, и всегда передавать его... Но не всегда определяйте в нем все.
например :
function foo($params) {
var_dump($params);
}
и называя это так:
foo(array(
'a' => 'hello',
));
foo(array(
'a' => 'hello',
'c' => 'glop',
));
foo(array(
'a' => 'hello',
'test' => 'another one',
));
вы получите этот вывод:
array
'a' => string 'hello' (length=5)
array
'a' => string 'hello' (length=5)
'c' => string 'glop' (length=4)
array
'a' => string 'hello' (length=5)
'test' => string 'another one' (length=11)
но мне это не очень нравится решение :
- Вы потеряете phpdoc
- ваша IDE больше не сможет предоставить никаких подсказок... Что плохо
поэтому я бы пошел с этим только в очень конкретных случаях - для функций с большим количеством параметров optionnal, например...
нет, PHP не может передавать аргументы по имени.
Если у вас есть функция, которая принимает много аргументов, и все они имеют значения по умолчанию, вы можете рассмотреть возможность принятия функции вместо массива аргументов:
function test (array $args) {
$defaults = array('a' => '', 'b' => '', 'c' => '');
$args = array_merge($defaults, array_intersect_key($args, $defaults));
list($a, $b, $c) = array_values($args);
// an alternative to list(): extract($args);
// you can now use $a, $b, $c
}
нет, это не так.
единственный способ сделать это-использовать массивы с именованными ключами, а что нет.
по состоянию на PHP 5.4 у вас есть синтаксис сокращенного массива (не nessecary, чтобы указать массивы с громоздким " массивом "и вместо этого использовать" []").
вы можете мимические именованные параметры во многих отношениях, один хороший и простой способ может быть:
bar('one', ['a1' => 'two', 'bar' => 'three', 'foo' => 'four']);
// output: twothreefour
function bar ($a1, $kwargs = ['bar' => null, 'foo' => null]) {
extract($kwargs);
echo $a1;
echo $bar;
echo $foo;
}
С PHP, порядок аргументов имеет значение. Вы не можете указать конкретный аргумент неуместным, но вместо этого вы можете пропустить аргументы, передав NULL, если вы не возражаете, что значение в вашей функции имеет значение NULL.
foo("hello", NULL, "bar");
Это не совсем красиво, но это делает трюк, можно сказать.
class NamedArguments {
static function init($args) {
$assoc = reset($args);
if (is_array($assoc)) {
$diff = array_diff(array_keys($assoc), array_keys($args));
if (empty($diff)) return $assoc;
trigger_error('Invalid parameters: '.join(',',$diff), E_USER_ERROR);
}
return array();
}
}
class Test {
public static function foobar($required, $optional1 = '', $optional2 = '') {
extract(NamedArguments::init(get_defined_vars()));
printf("required: %s, optional1: %s, optional2: %s\n", $required, $optional1, $optional2);
}
}
Test::foobar("required", "optional1", "optional2");
Test::foobar(array(
'required' => 'required',
'optional1' => 'optional1',
'optional2' => 'optional2'
));
вы можете сохранить phpdoc и возможность устанавливать значения по умолчанию, передавая объект вместо массива, например
class FooOptions {
$opt1 = 'x';
$opt2 = 'y';
/* etc */
};
Это также позволяет выполнять строгую проверку типа в вызове функции, если вы хотите:
function foo (FooOptions $opts) {
...
}
конечно, вы можете заплатить за это с дополнительной многословностью, настраивая объект FooOptions. К сожалению, нет абсолютно бесплатной поездки.
обычно вы не можете, но я думаю, что есть много способов передать именованные аргументы функции PHP. Лично я ретранслирую определение с помощью массивов и просто вызываю то, что мне нужно передать:
class Test{
public $a = false;
private $b = false;
public $c = false;
public $d = false;
public $e = false;
public function _factory(){
$args = func_get_args();
$args = $args[0];
$this->a = array_key_exists("a",$args) ? $args["a"] : 0;
$this->b = array_key_exists("b",$args) ? $args["b"] : 0;
$this->c = array_key_exists("c",$args) ? $args["c"] : 0;
$this->d = array_key_exists("d",$args) ? $args["d"] : 0;
$this->e = array_key_exists("e",$args) ? $args["e"] : 0;
}
public function show(){
var_dump($this);
}
}
$test = new Test();
$args["c"]=999;
$test->_factory($args);
$test->show();
живой пример здесь: http://sandbox.onlinephpfunctions.com/code/d7f27c6e504737482d396cbd6cdf1cc118e8c1ff
Если мне нужно передать 10 аргументов, и 3 из них являются данными, которые мне действительно нужны, даже не умно передавать в функцию что-то вроде
return myfunction(false,false,10,false,false,"date",false,false,false,"desc");
С подходом, который я даю, вы можете установить любой из 10 аргументов в массив:
$arr['count']=10;
$arr['type']="date";
$arr['order']="desc";
return myfunction($arr);
у меня есть сообщение в моем блоге, объясняющее этот процесс более подробно.
http://www.tbogard.com/2013/03/07/passing-named-arguments-to-a-function-in-php
вот что я использую. Определение функции принимает один необязательный аргумент массива, который задает необязательные именованные аргументы:
function func($arg, $options = Array()) {
$defaults = Array('foo' => 1.0,
'bar' => FALSE);
$options = array_merge($default, $options);
// Normal function body here. Use $options['foo'] and
// $options['bar'] to fetch named parameter values.
...
}
обычно вы можете звонить без каких-либо именованных аргументов:
func("xyzzy")
чтобы указать необязательный именованный аргумент, передайте его в необязательный массив:
func("xyzzy", Array('foo' => 5.7))
нет, не реально. Есть несколько альтернатив, которые вы могли бы использовать.
test(null,null,"hello")
или передать массив:
test(array('c' => "hello"));
тогда функция может быть:
function test($array) {
$c = isset($array[c]) ? $array[c] : '';
}
или добавьте функцию между ними, но я бы не предложил это:
function ctest($c) { test('','',$c); }
Я так не думаю... Если вам нужно позвонить, например, substr функция, которая имеет 3 парама, и хочет set в $Длина без установите $ start, вы будете вынуждены это сделать.
substr($str,0,10);
хороший способ, чтобы переопределить это всегда использовать массивы параметры
простой ответ. Нет, не можешь.
Вы можете попробовать обойти его, передав объект / массив или используя некоторые другие шаблоны инъекций зависимостей.
кроме того, попробуйте использовать нули, а не пустые строки, поскольку более определенно проверить их существование с помощью is_null()
например:
function test ($a=null,$b=null,$c=null){
if (is_null($a) {
//do something about $a
}
if (is_null($b) {
//do something about $b
}
if (is_null($c) {
//do something about $c
}
}
называть это:
test(null,null,"Hello");
короче говоря, иногда да, используя отражение и типизированные переменные. Однако я думаю, что это, вероятно, не то, что вам нужно.
лучшим решением вашей проблемы, вероятно, является передача 3 аргументов, поскольку функции обрабатывают отсутствующий внутри вашей функции самостоятельно
<?php
function test(array $params)
{
//Check for nulls etc etc
$a = $params['a'];
$b = $params['b'];
...etc etc
}
вы не можете сделать это способом python. Anway, вы можете передать ассоциативный массив и использовать записи массива по их имени:
function test ($args=array('a'=>'','b'=>'','c'=>''))
{
// do something
}
test(array('c'=>'Hello'));
это не уменьшает типизацию, но, по крайней мере, это более описательно, имея имена аргументов видимыми и читаемыми в вызове.
вот работа вокруг:
function set_param_defaults($params) {
foreach($params['default_values'] as $arg_name => $arg_value) {
if (!isset($params[$arg_name])) {
$params[$arg_name] = $arg_value;
}
}
return $params;
}
function foo($z, $x = null, $y = null) {
$default_values = ['x' => 'default value for x', 'y' => 'default value for y'];
$params = set_param_defaults(get_defined_vars());
print "$z\n";
print $params['x'] . "\n";
print $params['y'] . "\n";
}
foo('set z value', null, 'set y value');
print "\n";
foo('set z value', 'set x value');
кроме того: Лично я бы пошел с этим методом.
function foo($z, $x_y) {
$x_y += ['x' => 'default value for x', 'y' => 'default value for y'];
print "$z\n";
print $x_y['x'] . "\n";
print $x_y['y'] . "\n";
}
foo('set z value', ['y' => 'set y value']);
print "\n";
foo('set z value', ['x' => 'set x value']);
распечатки для обоих примеров.
1-й вызов:
- установить значение z
- значение по умолчанию для X
- установить значение y
2-й вызов:
- установить значение z
- установить значение x
- значение по умолчанию для y
просто используйте ассоциативный шаблон массива Drupal. Для необязательных аргументов по умолчанию просто примите