命名PHP可选参数?

时间:2009-08-27 18:26:01

标签: php default-value

在PHP 4/5中是否可以在调用时指定一个命名的可选参数,跳过你不想指定的参数(比如在python中)?

类似的东西:

function foo($a,$b='', $c='') {
    // whatever
}


foo("hello", $c="bar"); // we want $b as the default, but specify $c

由于

19 个答案:

答案 0 :(得分:21)

不,这是不可能的:如果要传递第三个参数,则必须传递第二个参数。并且命名参数也是不可能的。


一个“解决方案”是只使用一个参数,一个数组,并始终传递它......但不要总是在其中定义所有内容。

例如:

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将无法提供任何提示......哪个不好

所以我只在非常具体的情况下使用它 - 对于有很多可选参数的函数,例如......

答案 1 :(得分:6)

不,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       
}

See it in action

答案 2 :(得分:3)

不,不是。

你可以做到这一点的唯一方法是使用带有命名键的数组,而不是。

答案 3 :(得分:3)

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;
}

答案 4 :(得分:2)

使用PHP,参数的顺序才是最重要的。您不能指定一个特定的参数,而是可以通过传递NULL来跳过参数,只要您不介意函数中具有NULL值的值。

foo("hello", NULL, "bar");

答案 5 :(得分:2)

PHP 8 will be released on November 26, 2020.(PHP感恩节快乐!)

在此主要版本中,“ 命名参数”(又称“ 命名参数”)为开发人员在调用本机和自定义函数时提供了一些非常酷的新技术。

现在可以使用第一个参数(因为没有默认值)来调用此问题中的自定义函数,然后仅使用第三个参数(例如,{Demo

function foo($a, $b = '', $c = '') {
    echo $a . '&' . $b . '&' . $c;
}

foo("hello", c: "bar"); 
// output: hello&&bar

请注意,第二个参数不需要在函数调用中声明,因为它已定义了默认值-默认值将在函数内自动使用。

此新功能的部分优点在于,您无需注意命名参数的顺序-它们的声明顺序无关紧要。 foo(c: "bar", a: "hello");的工作原理相同。具有“跳过”声明和编写声明性参数的能力将提高脚本的可读性。这项新功能的唯一缺点是函数调用会有点膨胀,但是我(和许多其他人)认为收益超过了这种“成本”。

这里是一个本机函数的示例,它省略了limit参数,以正常顺序写入参数,并声明了一个引用变量。 (Demo

echo preg_replace(
         subject: 'Hello 7',
         pattern: '/[a-z ]/',
         count: $counted,
         replacement: ''
     )
     . " & " . $counted;
// output: H7 & 5

关于此新功能还有更多要说的。您甚至可以使用关联数组将命名参数传递给该函数,在该函数中,可以使用spread / splat运算符来解压缩数据!

(*请注意声明参考变量时稍有不同。)(Demo

$params = [
    'subject' => 'Hello 7',  // normally third parameter
    'pattern' => '/[a-z ]/', // normally first parameter
    // 'limit'               // normally fourth parameter, omitted for this demonstration; the default -1 will be used
    'count' => &$counted,    // normally fifth parameter
    //         ^-- don't forget to make it modifiable!
    'replacement' => '',     // normally second parameter
];
echo preg_replace(...$params) . " & " . $counted;
// same output as the previous snippet

有关更多信息,以下是一些线索,这些线索进一步解释了此功能以及一些常见的相关错误:(我与以下网站没有任何联系)

答案 6 :(得分:1)

它并不完全漂亮,但有些人可能会这样做。

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'
    ));

答案 7 :(得分:1)

您可以通过传递对象而不是数组来保持phpdoc和设置默认值的能力,例如

class FooOptions {
  $opt1 = 'x';
  $opt2 = 'y';
  /* etc */
};

如果您想:

,还可以在函数调用中进行严格的类型检查
function foo (FooOptions $opts) {
  ...
}

当然,您可能会为此设置FooOptions对象的额外详细程度。不幸的是,没有完全免费的旅程。

答案 8 :(得分:1)

通常你不能但我认为有很多方法可以将命名参数传递给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

答案 9 :(得分:0)

如果您真的想要,请尝试反射。 并跳过空值。

function getDefaultValueByNull($fn, $inputs) {
    $ref = new ReflectionFunction($fn);
    
    $args = array_map(function($p) {
        return [
            $p->getName(),
            $p->isDefaultValueAvailable() ? $p->getDefaultValue() : NULL,
        ];
    }, $ref->getParameters());

    foreach($inputs as $i=>$val) { if ($val!==NULL) $args[$i][1] = $val; }
    
    return array_column($args, 1, 0);
}

function sum($a=9, $b) {
    extract(getDefaultValueByNull(__FUNCTION__, func_get_args()));
    return $a+$b;
}
echo sum(NULL, 1); // 10

答案 10 :(得分:0)

只需使用Drupal使用的关联数组模式。对于可选的默认参数,只需接受一个$options参数,该参数是一个关联数组。然后使用数组+运算符设置数组中缺少的任何键。

function foo ($a_required_parameter, $options = array()) {
    $options += array(
        'b' => '',
        'c' => '',
    );
    // whatever
}

foo('a', array('c' => 'c’s value')); // No need to pass b when specifying c.

答案 11 :(得分:0)

这是一个解决方法:

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']);

打印两个例子。

第一个电话:

  • 设置z值
  • x
  • 的默认值
  • 设置y值

第二次电话:

  • 设置z值
  • 设置x值
  • y
  • 的默认值

答案 12 :(得分:0)

你不能用python方式做到这一点。 Anway,您可以传递一个关联数组,而不是按名称使用数组条目:

function test ($args=array('a'=>'','b'=>'','c'=>''))
{
    // do something
}

test(array('c'=>'Hello'));

这不会减少输入,但至少它更具描述性,让参数的名称在调用中可见且可读。

答案 13 :(得分:0)

非常简短,有时是,使用反射和类型变量。但是我认为这可能不是你想要的。

对你的问题更好的解决方案可能是传递3个参数,因为函数自己处理你函数中缺少的一个

<?php  
   function test(array $params)
   {
     //Check for nulls etc etc
     $a = $params['a'];
     $b = $params['b'];
     ...etc etc
   }

答案 14 :(得分:0)

简单的回答。不,你不能 您可以尝试通过传入对象/数组或使用其他一些依赖注入模式来解决它。

此外,尝试使用空值而不是空字符串,因为使用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");

答案 15 :(得分:0)

我不这么认为...... 如果您需要拨打substr功能,其中包含3个参数,并希望设置 $ length 而不设置$ start,则将被迫这样做。

substr($str,0,10);

一种很好的覆盖方法是始终使用数组作为参数

答案 16 :(得分:0)

尝试function test ($a="",$b="",&$c=""){}

&放在$c

之前

答案 17 :(得分:0)

不,不是真的。您可以使用它的一些替代方案。

test(null,null,"hello")

或传递数组:

test(array('c' => "hello"));

然后,该功能可以是:

function test($array) { 
    $c = isset($array[c]) ? $array[c] : '';
}

或者在两者之间添加一个函数,但我不建议这样做:

function ctest($c) { test('','',$c); }

答案 18 :(得分:0)

这是我一直在使用的。函数定义采用一个可选的数组参数,该参数指定可选的命名参数:

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))