【问题标题】:Using an associative array as php function's input使用关联数组作为 php 函数的输入
【发布时间】:2010-11-03 02:11:41
【问题描述】:

有时我会编写一个带有单个输入的 PHP 函数,一个包含该函数所有输入的关联数组。这有一些好处,例如不必记住输入的正确顺序,但我也注意到它使对大型代码库的更改变得更加容易;当我需要添加另一个变量,并且该变量必须通过 4 或 5 个预先存在的函数时,我可以将它粘贴到数组中并传递它会容易得多。

我的问题是,这样做有缺点吗?

我很少在示例中或在我使用的开源代码中看到以这种方式编写的函数,这让我相信可能存在缺点。如果没有理由不这样做,那为什么不把所有的函数都写成这样呢?

更新

感谢您的所有回答。看起来有两个主要问题很突出:

代码可读性 - 无法分辨哪些变量将进入函数以及它们的用途

变量蠕变 - 最终可能会出现大量数组从一个函数弹跳到下一个函数;不应将参数传递给不需要它们的函数

这两个都是我没有想到的好点。

似乎一般要点是,存在问题的代码可能应该转换为类。不幸的是,在这个特定的项目中,这样的重构超出了范围,但我也认为 Bill Karwin 的解决方案很好——传递一组可选变量

【问题讨论】:

  • 出于兴趣,您可以发布一个您将编写的示例函数吗? :)
  • @Shadi - 更像是“出于病态的好奇心”? :)
  • 所以不是 function myFunc($var1, $var2, $var3, $var4 ...) {} 你有 function myFunc($params) { } 然后通过 $params[ 'var1']等
  • 如果你好奇的话,“命名参数”的概念已经被 PHP 内部团队讨论过好几次了,但都是ultimately rejected

标签: php arrays object function


【解决方案1】:

为什么不把所有的函数都写成这样呢?

就此而言,为什么不完全忘记参数,而对所有事物都使用全局变量呢? (开玩笑)

传递关联数组有一个有用的优点:可以使多个函数参数成为可选参数,并且可以为第 N 个参数传递一个值,而不必为 *N-1 传递一个值*第一个参数。

但是,如果您不传递强制参数,则无法生成编译时错误。你也不能声明类型检查。

您必须在被调用函数中编写代码来检查所需参数的存在和类型。

我使用的另一种方法是为强制性参数声明常规参数,然后作为最后一个(可选)参数声明一个名为 $options 的关联数组,其中仅包含可选项。

function database_connect($dbname, $user, $password, array $options = array())

【讨论】:

  • 你也不能声明类型检查——你能解释一下如何做到这一点吗?例如,在您的示例函数中,我们可以在函数声明中将$password 类型检查为字符串吗?我假设您打算在函数本身内部对其进行类型检查,对吧?
  • 我的意思是对 array 或类类型进行类型检查,在参数列表中声明(当我在 2009 年写这篇文章时,PHP 在标量类型的参数列表中没有类似的类型检查像字符串、整数、浮点数)。如果使用 $options 数组,则必须在函数中手动进行所有类型检查;您不能以声明方式进行。
  • 知道了,谢谢。到目前为止,PHP 仍然是一种弱类型语言,不是吗?我的意思是你不能指定变量的类型,例如int、float 等。
  • @Bill Karwin,我需要为上传图片创建一个函数,但我不知道如何为函数()创建一个输入变量,例如 $_FILES['file']['错误']
  • @Kermani,我不明白你想做什么。我建议您提出一个新问题,并描述您想要实现的目标、到目前为止您尝试了什么,以及它如何没有达到您想要的效果。
【解决方案2】:

不利的一面是,任何查看您的代码的人(除了您)都不知道方法中的参数是什么,它们来自哪里,或者它们的用途。他们也不知道如何调用方法,因为如果不查看代码就不清楚该“参数数组”中究竟需要什么。

【讨论】:

  • 这是正确的,前提是编码人员不发表评论或记录任何内容。
【解决方案3】:

可能的缺点之一是您最终会得到太多参数。 这导致代码很可能失去可读性的问题。

在严格的面向对象方法中,您可以将“通过”多个函数调用的所有这些参数转换为包含方法的类的实例变量。

你不应该将参数传递给它们实际上不需要的函数。

【讨论】:

  • 虽然如果你有function foo($a, $b) { ... } 并且从调用者的角度来看只有$b 很重要,你可能最终会传递一个不必要的值作为第一个参数以符合函数要求。
【解决方案4】:

这并不一定是个坏主意,因为 PHP 缺少许多其他现代编程语言(Python、Ruby 等)中的“关键字参数”功能。但是,它肯定存在一些问题:

  1. 如果您更改函数接受的参数,那么很可能您必须更改一些调用它的代码,以匹配新参数。

  2. 如果您广泛使用这些数组,并且在许多函数调用中获取一个数组并简单地“传递它”,这可能表明您应该考虑将其中一些参数转换为结构化类.

  3. 如果您将这些数组用作可变数据结构,您不一定知道调用函数后的数组与您传入的数组相同。这可能会回到在某个时候得到你。

【讨论】:

    【解决方案5】:

    列出每个参数可以增加代码的可读性。传递单个关联数组不一定能解释传递给函数的数据类型。

    【讨论】:

      【解决方案6】:

      如果我拿起你的函数并看到它只是开始在单个函数参数中引用哈希值,我会有点困惑。使用@param 明确说明变量并在文档块中提供一些文档非常有帮助。与列出参数的可读性相比,必须在两个地方添加参数是一个很小的成本。

      【讨论】:

        【解决方案7】:

        我个人使用如下方法:

        1. 在函数定义中将参数声明为数组;

        2. 建立一个“默认值”关联。数组;

        3. 将传递的参数与默认值匹配到我在函数内部使用的明确参数 assoc.array 中。为此,我使用了 param_default() 函数。

        通过遵循这种方法,我避免了强制参数问题并管理默认值;以任何顺序传递密钥的能力也非常舒适。

        // default values fx.
        function param_default( $def = array(), $parameters= array() ){
            $parm_diff = array();
            $ak=array();
            $va=array();
            $parm = array();
            foreach($def as $key=>$values) if(!in_array($key, array_keys($parameters))){
                $ak[]=$key;
                $va[]=$values;
            }
            $parm_diff = array_combine($ak,$va);
            $parm = array_merge($parm_diff,$parameters);
            unset($parm_diff, $ak,$va);
        
            return $parm;
        }
        

        所以这是一个简单的用法示例:

        <?php
        // sample use 
         function my_func( $parameters = array() ){
            $def = array(
                'first' => 1,
                'second' => 'foo',
                'third' => -1
             );
           $parm = param_default( $def, $parameters );
           //hereon I can use my array
        
           var_dump($param);
        
           if ($param['second'] !=='foo'){
               echo 'Not foo!!';
               // whatever...
           }
        
           return true;
        }
        ?>
        

        输出示例:

         // calling my_fun()
        
        $example = my_func( array('second'=>'bar') );
        
        // results in 
        $param array: 
        'first' => 1,
        'second' => 'bar',
        'third' => -1
        

        【讨论】:

          【解决方案8】:

          这里最大的代码异味是添加另一个变量会级联 4-5 个不同的函数。我真的想不出为什么会发生这种情况。

          听起来您需要将此代码重构为一个类,以便您可以将值一次性传递给构造函数,并将它们保存为成员变量。

          【讨论】:

            【解决方案9】:

            如果您有单独命名和传入的参数,则生成文档会容易得多。您可能会认为使用数组可以更轻松地添加新代码,但它的好处并没有超过可读性。再加上离开你的代码 2 个月然后回来......弄清楚以什么顺序将参数添加到你的数组中,在哪些情况下会变得非常头疼。

            【讨论】:

              【解决方案10】:

              在某些情况下,我觉得这确实是有道理的,但通常您可以通过创建多个行为略有不同的方法来简化事情。然后方法的名称将清楚地说明它的用途。

              一般来说,如果你的函数有 > 3 个参数,它无论如何都会变得不可读。

              作为一种替代方法,并且经常使用的模式是使函数的单个参数成为(分类)对象。 “参数类”将准确定义支持的内容。

              【讨论】:

                【解决方案11】:

                如果有人仍在寻找解决方案 - 在这里(示例函数是 __construct() ):

                Extract $_GET/$_POST params and pass them to constructor

                【讨论】:

                  【解决方案12】:

                  如果您的问题是如何将数组作为 inputof 函数,这就是您的答案:

                  <?php
                   function city($input){
                     $i=count($input['iran']);
                     $result="";
                       for($b=1;$b<=$i;$b++){
                         $result.='<div style="background:gold">'.$input['iran'][$b].'</div>';
                         }
                        return $result;
                      }
                  $cityName['iran'][1]="Tehran";
                  $cityName['iran'][2]="Qom";
                  $cityName['iran'][3]="MashHad";
                  $cityName['iran'][4]="Isfahan";
                  $cityName['iran'][5]="Shiraz";
                  $cityName['iran'][6]="Yazd";
                  
                  echo city($cityName);
                  ?>
                  

                  【讨论】:

                    【解决方案13】:

                    创建函数:

                    function testing($argumentos) {
                        $var_1 = $argumentos['var_01'];
                        $var_2 = $argumentos['var_02'];
                    
                        echo $var_1 . " " . $var_2;
                    } 
                    

                    调用函数:

                    testing(array('var_01' => "mierda", 'var_02' => "conio!"));
                    

                    输出:

                     mierda conio!
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2021-03-13
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2015-05-31
                      • 2015-11-25
                      • 1970-01-01
                      相关资源
                      最近更新 更多