【问题标题】:PHP Function Arguments - Use an array or not?PHP 函数参数 - 是否使用数组?
【发布时间】:2012-04-28 11:05:41
【问题描述】:

我喜欢使用 key=>value 对(数组)作为参数而不是单个参数来创建我的 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 代码库中广泛使用这种方式。

我喜欢数组的原因:

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

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

我正在寻求专家的一般建议和指导,他们可能能够提供见解:有什么更好或更合适的方法来做到这一点?

【问题讨论】:

  • 我不明白为什么人们大多反对以你提到的方式传递它。我认为这是一种灵活的方式,即使有人正在处理你的功能。我正在开发一个框架,它需要raw_queries 和其他一些东西。解析参数数组的能力使其非常灵活。
  • @ethanpil 如果您仍然在此问题上 - 我在今天提出的类似问题 stackoverflow.com/questions/51751753/… 中链接到您的问题,并且得到的答案超出了人们在这里谈论的范围。他们告诉我,做你和我正在做的事情的更好方法是为参数中的信息创建一个类,并且函数成为该类的方法。我接受的答案提供了一些将我们的数组技术翻译成对象语言的代码。我认为这看起来是一种更好、更复杂的方法。

标签: php arrays function arguments


【解决方案1】:

嗯,有点用处。但是对于某些总是通过的参数,最好使用像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 可以控制更多的东西,如果我使用你的代码风格,我应该这样做。

【讨论】:

  • "core" 参数是主观的,可能会导致 args 的圣诞列表。如果你遵循2个以上的硬性规定,应该是一个数组,不管是否核心。
【解决方案2】:

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

当然,从数组中推断值需要更多的工作,而且您确实必须考虑所需的元素,但它确实使添加特性变得更加容易,并且比每次向函数传递 13 个参数要好得多需要调用它的时间。

这是一个显示必需参数和可选参数的代码的 sn-p,只是为了给你一个想法:

// 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();

....

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 你看到上面的@devdRew 了吗,你会说array_merge() 函数仍然会“慢”吗?
    • 这是一种“冬青战争”,在数组参数中使用或不使用聚合,但如果你说使用单独的参数更简单,例如将一些记录存储到数据库中传递的值,您不会将每个行值用作单独的参数。对吗?
    【解决方案4】:

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

    如果你是唯一一个会处理你的代码的人,那么你可以做你喜欢做的事。但是,通过将所有参数值传递给数组,其他任何人都将不得不更加努力地理解该函数的作用以及他们为什么/如何使用它,特别是如果他们使用的是具有函数名称自动完成功能的 IDE等等。他们不会无缘无故地将其称为“功能签名”。

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

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

    【讨论】:

    • 我认为适当的文档可以作为一个非常有效的“解决该问题的步骤”。
    • 我听到你在说什么,但如果你的代码写得很好,它应该主要是自我记录的,在这种情况下你不需要“记录”它(例如使用 cmets等等。)。这也解决了当代码与“文档”不同步时可能出现的问题。
    【解决方案5】:

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

    如果您发现您正在编写大量参数,尤其是可选参数,则表明您的设计可能存在问题。考虑一下你可能会怎么做。如果部分或全部参数是相关的,那么它们可能属于它们自己的类。

    【讨论】:

      【解决方案6】:

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

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

      另请参阅:Function Passing array to defined key

      使用数组作为函数参数时你不会得到的一些东西是:

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

      【讨论】:

        【解决方案7】:

        @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();
        

        ....

        相同的实现,但更短。

        【讨论】:

          【解决方案8】:

          我在很多场合都使用数组来替换一长串参数,并且效果很好。我同意这篇文章中提到的关于代码编辑器无法为参数提供提示的人的观点。问题是,如果我有 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() 函数在一定程度上认识到了这一点,该函数允许以任何顺序传递参数。但是这只会传递值的副本,所以如果你想将对象传递给函数,这将是一个问题。如果存在这样的函数,那么代码编辑器将能够选择它并提供有关可能参数的详细信息。

          【讨论】:

            【解决方案9】:

            不要那样做!

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

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

            这似乎与 injecting 的功能相反。

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

            我没有这样的偏好。我不明白这种需求。

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

            大多数 IDE 会为您提供函数所需的不同参数。如果看到像foo(Someclass $class, array $params, $id) 这样的函数声明,就很清楚该函数需要什么。我不同意单个参数参数更易于阅读或自我记录。

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

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


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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2010-11-28
              • 1970-01-01
              • 2022-06-13
              • 1970-01-01
              • 2013-10-08
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多