繁体   English   中英

PHP函数参数 - 是否使用数组?

[英]PHP Function Arguments - Use an array or not?

我喜欢使用key => value pairs(数组)作为参数而不是单个参数来创建我的PHP函数。

例如,我更喜欢:

function useless_func($params) {
    if (!isset($params['text'])) { $params['text'] = "default text"; }     
    if (!isset($params['text2'])) { $params['text2'] = "default text2"; }   
    if (!isset($params['text3'])) { $params['text3'] = "default text3"; }   
    echo $params['text'].$params['text2'].$params['text3'];
    return;
}

我不喜欢:

function useless_func($text = "default text", $text2 = "default text2", $text3 = "default text3") {
        echo $text.$text2.$text3;
    return;
}

我第一次看到在Wordpress代码库中广泛使用这种方式完成的事情。

我更喜欢数组的原因:

  • 函数参数可以按任何顺序提供
  • 更容易阅读代码/更多自我记录(在我看来)
  • 不容易出错,因为在调用函数时我必须调查正确的数组键

我正在与同事讨论这个问题,他说它没用,只会导致额外的代码,而且设置默认值要困难得多。 基本上,他完全不同意我的所有三点。

我正在寻找可能提供见解的专家的一般建议和指导:有什么更好或更正确的方法来做到这一点?

嗯,这有点有用。 但对于一些传递总是最好使用经典传递function some($a1, $a2) 我在我的代码中这样做:

function getSome(SomeClass $object, array $options = array())
{
    // $object is required to be an instance of SomeClass, and there's no need to get element by key, then check if it's an object and it's an instance of SomeClass

    // Set defaults for all passed options
    $options = array_merge(array(
        'property1' => 'default1',
        'property2' => 'default2',
        ... => ...
    ), $options); 
}

所以,你可以看到我也喜欢那种代码风格,但是对于核心参数我更喜欢经典风格,因为如果我使用你的代码风格,PHP会控制更多的东西。

不要那样做!

在大多数情况下,将所有数据传递到数组中是个坏主意。

  • 它可以防止人们在不知道操作需要的情况下使用您的功能。
  • 它允许您创建需要大量参数的函数,可能您应该创建一个具有更精确的参数需求和更窄目标的函数

在功能中注入它需要的东西似乎相反。

函数参数可以按任何顺序提供

我没有这样的偏好。 我不明白这个需要。

更容易阅读代码/更多自我记录(在我看来)

大多数IDE将为您提供函数所需的不同参数。 如果有人看到像foo(Someclass $class, array $params, $id)这样的函数声明foo(Someclass $class, array $params, $id) ,那么函数需要的是什么。 我不同意单个参数论证更容易阅读或自我记录。

不容易出错,因为在调用函数时我必须调查正确的数组键

允许人们在不知道值将被默认的情况下传入数组并不接近“不容易出错”。 让人们在使用它之前必须阅读你的功能是一种永远不会被使用的可靠方法。 声明它需要三个参数及其默认值是容易出错的,因为调用函数的人将知道参数将默认为哪些值,并相信它将呈现他们期望的结果。


如果您要解决的问题是参数太多,那么正确的决定是将您的函数重构为较小的函数,而不是隐藏数组后面的函数依赖项。

我假设你问的是,编写所有函数是否是一件好事 ,以便它们只接受一个参数,并且该参数是一个数组?

如果你是唯一一个能够使用你的代码的人,那么你可以做你喜欢的事。 但是,通过将所有参数值传递给数组,其他任何人都必须更加努力地了解函数的作用以及它们为何/如何使用它,特别是如果它们使用具有自动完成功能名称的IDE他们并没有把它称为“功能签名”。

我建议数组参数保留用于你不知道有多少项的项目(例如一系列数据项),或者用于相关选项/设置组(可能是Wordpress中正在发生的事情)你提到的例子?)。

如果你继续采用数组参数的一揽子方法,那么你至少应该意识到它对可读性的影响,并采取一些措施来解决这个问题。

你的同事是对的。 它不仅是相同功能的更多代码,更难以阅读并且可能降低了性能(因为您需要为每个参数调用isset ,并且您需要访问数组来设置值)。

这与货物崇拜编程接壤。 你说这更具可读性和自我记录性。 我会问怎么样? 要知道如何使用您的函数/方法,我必须阅读代码本身。 我无法从签名本身知道如何使用它。 如果您使用支持方法签名提示的任何半正式IDE或编辑器,这将是一个真正的PITA。 另外,您将无法使用PHP的类型提示语法。

如果您发现编码了大量参数,特别是可选参数,则表明您的设计可能存在问题。 考虑一下你可能会怎么做。 如果某些或所有参数相关,那么它们可能属于他们自己的类。

使用array_merge()可以正常工作,但也可以使用+运算符; 它以另一种方式工作,它只添加一个尚未给出的默认值。

function useless_func(array $params = array())
{
    $params += array(
        'text' => 'default text',
        'text2' => 'default text2',
        'text3' => 'default text3',
    );
}

另请参见: 函数将数组传递给已定义的键

使用数组作为函数参数时,您无法获得的一些事情是:

  1. 类型检查(仅适用于对象和数组,但它可能很有用,在某些情况下是预期的)。
  2. smart(er)文本编辑器具有代码洞察功能,可以显示函数理解的参数; 尽管您可以在函数docblock中添加可能的键,但使用数组会删除该功能。
  3. 由于#2实际上它更容易出错,因为您可能会错误输入数组键。

你的同事很疯狂。 传递数组作为函数参数是完全可以接受的。 它在包括Symfony和Doctrine在内的许多开源应用程序中很流行。 我总是遵循2参数规则,如果一个函数需要两个以上的参数,或者你认为将来会使用两个以上的参数,请使用数组。 IMO允许最大的灵活性并减少在参数传递不正确时可能出现的任何调用代码缺陷。

当然,从数组中推断出值需要更多的工作,你必须考虑所需的元素,但它确实使添加功能更容易,并且比每次需要时将13个参数传递给函数要好得多被称为。

这是一段显示所需与可选参数的代码,只是为了给你一个想法:

// Class will tokenize a string based on params
public static function tokenize(array $params)
{
    // Validate required elements
    if (!array_key_exists('value', $params)) {
        throw new Exception(sprintf('Invalid $value: %s', serialize($params)));
    }        

    // Localize optional elements
    $value            = $params['value'];
    $separator        = (array_key_exists('separator', $params)) ? $params['separator'] : '-';
    $urlEncode        = (array_key_exists('urlEncode', $params)) ? $params['urlEncode'] : false;
    $allowedChars     = (array_key_exists('allowedChars', $params)) ? $params['allowedChars'] : array();
    $charsToRemove    = (array_key_exists('charsToRemove', $params)) ? $params['charsToRemove'] : array();

....

@Mike,你也可以将你的$ params参数“解压缩”到局部变量中,如下所示:

// Class will tokenize a string based on params
public static function tokenize(array $params)
{
    extract($params);
    // Validate required elements
    if (!isset($value)) {
        throw new Exception(sprintf('Invalid $value: %s', serialize($params)));
    }

    // Localize optional elements
    $value         = isset($value) ? $value : '';
    $separator     = isset($separator) ? $separator] : '-';
    $urlEncode     = isset($urlEncode) ? $urlEncode : false;
    $allowedChars  = isset($allowedChars) ? $allowedChars : array();
    $charsToRemove = isset($charsToRemove) ? $charsToRemove : array();

....

相同的实现,但更短。

我已经使用数组在很多场合替换了很长的参数列表并且运行良好。 我同意这篇文章中那些提到代码编辑无法提供参数提示的人。 问题是,如果我有10个参数,并且前9个为空/ null,则在调用该函数时它变得难以处理。

我也有兴趣听听如何重新设计一个需要大量参数的函数。 例如,当我们有一个函数根据设置的某些参数构建SQL语句时:

function ($a1, $a2, ... $a10){

        if($a1 == "Y"){$clause_1 = " something = ".$a1." AND ";}
        ...
        if($a10 == "Y"){$clause_10 = " something_else = ".$a10." AND ";}

        $sql = "
        SELECT * FROM some_table 
        WHERE
        ".$clause_1." 
        ....
        ".$clause_10." 
        some_column = 'N'
        ";

        return $sql;
    }

我希望看到PHP能够添加一个本机帮助函数,该函数可以在被调用的函数中使用,这将通过进行必要的类型检查来帮助传递参数数组。 PHP在某种程度上通过创建func_get_args()函数来识别这一点,该函数允许以任何顺序传递参数。 但这只会传递值的COPY,所以如果你想将对象传递给函数,这将是一个问题。 如果存在这样的函数,那么代码编辑器将能够选择它并提供有关可能参数的详细信息。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM