3

我有一些 php 函数,它们有大量带有默认值的参数。像这样的东西:

function foo($a=0,$b=6,$c=2,...

我想知道我能做些什么来避免立场争论的恐怖。是否可以仅使用参数集的一个子集并按名称调用该函数?如:

foo($c=37)

谢谢!

4

5 回答 5

8

显然 ,避免位置参数可怕的最好方法是避免使用长而多风的参数列表的函数。

您可以通过单个数组变量传递大部分参数,或者您需要重构您的函数,将它们拆分为更小的函数或将它们组合到一个类中

于 2013-09-13T12:22:04.790 回答
3

我完全理解这个问题的出处,但我必须说:如果你的函数需要一系列参数,这些参数是可选的,9/10 你的函数有问题。
现实生活中的功能是做某事的能力。在现实世界中,椅子是可以坐的东西。它可以有N条腿,但它只能完成一项工作。随着时间的推移,在我看到的许多代码中,具有太多可选参数的函数执行不同的任务,具体取决于传递给它的参数。因此,该功能有超过 1 个任务。这不是函数的用途!

请重新考虑你的逻辑。但是,如果您的函数只完成一项工作,而不管指定了哪些参数,@OZ_ 的答案就是:类型提示(通过类名或接口)是执行此操作的正确方法。
关联数组也可以使用,为了避免编写大量的if' 之类的:

$a = 'default';
if (isset($args['a']))
{
    $a = $args['a'];
}
$b = isset($args['b']) ? $args['b'] : 'default';//or messy ternary-packed code

你可能会选择这样写:

function someF(array $args)
{
    $a = $b = $c = $d = null;//all your arguments and default values
    foreach($args as $name => $val)
    {
        $$name = $val;
    }
    //function body
}
someF(range(1,3));//works, but sets ${'0'}, ${'1'}, ...
someF(array('a' => 1));//works fine
someF(array('a' => new stdClass));//is $a going to be the right type?

尽管如此,就像在if's/ternary 方法中一样,您无法预测值将是哪些类型,也不知道正在传递什么类型的数组(asoc/numeric),因此您最终可能会设置很多您不知道的变量不需要。另外,从现在起几个月后,您会称这段代码易于阅读/调试/维护吗?

另一方面,使用类或接口:

class ArgumentsForFunc
{
    private $a = null;
    private $email = null;
    public function setA($val = null)//defaults to default value...
    {
        $this->a = $val === null ? null : (int) $val;//cast to correct type
        return $this;
    }
    public function getA()
    {
        return $this->a;
    }
    public function setEmail($email = null)
    {
        if (!$email || !filter_var($email, FILTER_VALIDATE_EMAIL))
        {//check data here!
            $email = null;
            //or better yet:
            throw new InvalidArgumentException((string) $email.' is not a vaild email address');
        }
        $this->email = $email;
        return $this;
    }
    public function getEmail($default = null)
    {
        return $this->email ? : $default;
    }
}

这个类的工作很明确:它保存通过 setter 接收的数据。这些 setter 方法验证原始数据,并可以抛出异常或转换为正确的类型。这意味着您可以像这样使用它:

function betterF(ArgumentsForFunc $args)
{
    $a = $args->getA();
    $email = $args->getEmail('default@email.arg');
    echo 'send ', $a, ' mails to ', $email;
}
$arg = new ArgumentsForFunc;
$arg->setA(2);
betterF($arg);//send 2 mails to default@email.arg

现在您可以放心,只要用户传递 的实例ArgumentsForFunc,您的函数就会按照您的预期运行。当然,这种方法最初需要您编写更多代码,但它会为您省去大量调试麻烦,并使测试变得容易得多。

PS:在数据模型中抛出异常。如果设置的数据无效,请尽快通知用户。当调用 setter 时立即抛出异常时,您可以轻松地跟踪错误。如果你不这样做(并且默默地失败),你可以花几个小时试图找出你的getEmail电话返回的原因null,而不是你认为你传递给其他地方的 setter 的电子邮件地址。

于 2013-09-13T12:17:28.440 回答
1

还没有。具有多个参数的函数可以替换为具有一个参数的函数,数据结构(在 php 中,它是没有方法和公共字段的类)。

function foo(FooSet $fooSet){
}

class FooSet{
 public $a = 0;
 public $b = 6;
 public $c = 2 ;
}

并且不要为此使用数组 - 这是一种称为“面向数组的编程”的坏习惯。

于 2013-09-13T12:06:21.277 回答
1

如果你有这么多参数,为什么不使用一个对象并__invoke

class FuncClass {

    public $a = 4;
    public $b = 4;
    public $c = 4;
    public $d = 4;
    ...

    function __invoke() {
    }

}

利用:

$func = new FuncClass();
$func->a = 3;
$func();
于 2013-09-13T12:06:49.083 回答
0

您不能在 PHP 中使用命名参数。

将数组用作单个参数并将实际参数放入数组中。

$arguments["a"]=1;
$arguments["b"]=2;
$arguments["c"]=3;


function args_test($arguments) {
   extract($arguments);
   echo $a.$b.$c;
}

args_test($arguments) 将输出 123。

在函数的开头将允许您将它们用作适当的参数

于 2013-09-13T12:07:37.270 回答