【问题标题】:Optional parameters in PHP function without considering orderPHP函数中的可选参数不考虑顺序
【发布时间】:2019-02-03 12:21:19
【问题描述】:

在 PHP 中是否有一种方法可以使用在其声明中具有可选参数的函数,我不必传递已经声明了值的可选参数,而只需传递具有不同值的下一个参数进一步向下的参数列表。

假设我有一个有 4 个参数的函数,其中 2 个是必需的,2 个是可选的。我不想对可选参数使用空值。在使用中,有些情况我想使用该函数,并且第 3rd 参数的值与默认值相同,但第 4th 参数的值是不同的。

我正在寻找一个不那么冗长的解决方案,它允许我只传递与默认值不同的参数,而不考虑函数声明中的顺序。

  createUrl($host, $path, $protocol='http', $port = 80) {
    //doSomething
    return $protocol.'://'.$host.':'.$port.'/'.$path;
  }

我发现自己重复声明变量以便我可以使用函数,即使用 $port,我用函数范围之外的默认值重新声明 $protocol,即

$protocol = "http";
$port = 8080;

有没有办法在不传递 $protocol 的情况下传递第二个可选参数($port),它会“自动”填充 $protocol 的默认值,即

 getHttpUrl($server, $path, $port);

这在某些语言中是可能的,例如 Dart,以命名可选参数的形式出现。请参阅此 SO 线程中的用法。他们在 PHP 中是否有类似的解决方案

【问题讨论】:

  • 我也同样对此感到好奇,但这也是在设计函数/方法时对参数进行排序的重要性所在。
  • 我觉得这不是您真正的问题,但您将其用作添加示例,仅作为示例。有一些方法可以解决您在此处向我们展示的问题,但可能无法将该解决方案应用于您的实际问题。你能澄清一下吗?
  • 另一种可能是使用Variable-length argument lists
  • @SeverinDK 将编辑和澄清
  • 是的。一个函数(或者你作为一个编码器)有两种可能来区分传入的参数:顺序或类型。或者您使用@ChrisForrence 在他的回答中描述的构造。所以你的问题的答案是:不。但是您可以在答案中找到解决方法。

标签: php


【解决方案1】:

嗯,这应该可行:

function myFunc($arg1, $arg2, $arg3=null, $arg4= null){
  if ( is_null( $arg3 ) && is_null( $arg4 ) {
    $arg3 = 3;
    $arg4 = 4;
  } else if ( is_null( $arg4 ) ) {
    $arg4 = $arg3;
    $arg3 = 3;
  }
    echo $arg1 + $arg2 + $arg3 + $arg4;
}

但是我建议你重新考虑你的问题(作为一个整体),因为这不是一个好主意。

【讨论】:

    【解决方案2】:

    你的问题有答案,你可以像这样声明你的函数

    function myFunc($arg1, $arg2, $arg3 = null, $arg4 = null){
        //here you check if the $arg3 and $arg4 are null
    }
    

    然后你调用你的函数使用

    myFunc($arg1, $arg2);
    

    【讨论】:

    • 但是他/她想打电话给myFunc($arg1, $arg2, NOTHING, $arg4);
    • 谢谢。我不想有空值。寻找一种我不必传递已经具有默认值的参数的方法。
    【解决方案3】:

    你可以potentially为此使用可变参数函数。

    例子:

    <?php
    
    function myFunc(...$args){
        $sum = 0;
        foreach ($args as $arg) {
            $sum += $arg;
        }
    
        return $sum;
    }
    

    文档: http://php.net/manual/en/functions.arguments.php#functions.variable-arg-list

    【讨论】:

      【解决方案4】:

      PHP 中没有这种方式(例如在 python 中)。

      您必须使用一些技巧才能做到这一点,但并不总是有效。 例如:

      // creates instances of a class with $properties.
      // if $times is bigger than 1 an array of instances will be returned instead.(this is just an example function)
      function getInstance($class, $properties = [], $times = 1){
          //my code
      }
      
      $user = getInstance("User", ["name" => "John"]); // get one instance
      $users = getInstance("User", ["name" => "John"],2); // get two instances.
      

      如果你想使用函数而不传递$parameters 参数,像这样:

      $users = getInstance("User",2);

      您可以将函数更改为:

      // creates instances of a class with $properties.
      // if times is bigger than 1 an array of instances will be returned instead.
      function getInstance($class, $properties = [], $times = 1){
          if(is_numberic($properties)){
              $times = $properties;
              $properties = [];
          }
          //my code
      }
      

      当然,此策略仅在您的参数具有不同类型时才有效。

      附言。这种方法在 Laravel 框架中被大量使用。从那里我得到了灵感。

      【讨论】:

      • 谢谢。您的解决方案的弱点是按类型检查。
      • 不幸的是
      【解决方案5】:

      您可以将其重构为使用parameter object;这样,您可以在此对象中包含默认参数并以任何顺序设置它们(权衡更冗长的代码)。作为使用上述代码的示例,

      <?php
      
      class AdditionParameters
      {
          private $arg1 = 0;
          private $arg2 = 0;
          private $arg3 = 3;
          private $arg4 = 4;
      
          public function getArg1() { return $this->arg1; }
          public function getArg2() { return $this->arg2; }
          public function getArg3() { return $this->arg3; }
          public function getArg4() { return $this->arg4; }
      
          public function setArg1($value) { $this->arg1 = $value; return $this; }
          public function setArg2($value) { $this->arg2 = $value; return $this; }
          public function setArg3($value) { $this->arg3 = $value; return $this; }
          public function setArg4($value) { $this->arg4 = $value; return $this; }
      }
      

      从那里,您可以在传入这个新对象时简单地调用该函数。

      function myFunc(AdditionParameters $request) {
          return $request->getArg1()
              + $request->getArg2()
              + $request->getArg3()
              + $request->getArg4();
      }
      
      echo myFunc((new AdditionParameters)->setArg1(1)->setArg2(2)->setArg4(6));
      // or echo myFunc((new AdditionParameters)->setArg1(1)->setArg4(6)->setArg2(2));
      

      否则,PHP 不允许您命名可选参数。 (例如myFunc(1, 2, DEFAULT, 4);

      【讨论】:

        【解决方案6】:

        PHP 不允许在这种状态下按我们想要的顺序调用函数参数。也许将来会。但是您可以通过使用关联数组作为唯一参数轻松实现您的目的,然后定义函数中的默认参数。对于调用,您需要传递一个仅包含您感兴趣的值的数组。该数组将与默认数组合并。您甚至可以实现所需的参数并以您想要的任何顺序调用它们。 示例:

            function mysweetcode($argument){
            $required=['first'];//specify required parameters here
            $default=['first'=>0,'second'=>1,'third'=>2];//define all parameters with their default values here
            $missing=[];
            if(!is_array($argument)) return false;
            $argument=array_intersect_key($argument,$default);
            foreach($required as $k=>$v){//check for missing required parameters
                if(!isset($argument[$v]))
                    $missing[]=$v;
            }
            if(!empty($missing)){// if required are missing trigger or throw error according to the PHP version 
                $cm=count($missing);
                if (version_compare(PHP_VERSION, '7.0.0') < 0) {
                    trigger_error(call_user_func_array('sprintf',
                    array_merge(array('Required '.(($cm>1)?'parameters:':'parameter:').
                    str_repeat('%s,',$cm).(($cm>1)?' are':' is').' missing'),$missing)),
                    E_USER_ERROR);
                }else{
                    throw new Error(call_user_func_array('sprintf',array_merge(
                    array('Required '.(($cm>1)?'parameters:':'parameter:').
                    str_repeat('%s',$cm).(($cm>1)?' are':' is').' missing'),$missing)));
                }
            }
            $default=array_merge($default,$argument);//assign given values to parameters
            extract($default);/*extract the parameters to allow further checking    
            and other operations in the function or method*/
            unset($required,$missing,$argument,$default,$k,$v);//gain some space 
        
            //then you can use $first,$second,$third in your code
        
            return $first+$second+$third;
        
        }  
        
        var_dump(mysweetcode(['first'=>9,'third'=>8]));//the output is 18
        
        var_dump(mysweetcode(['third'=>8]));//this throws Error on PHP7 and trigger fatal error on PHP5 
        

        您可以查看live working code here

        【讨论】:

        • 这是我正在寻找的方向,尽管我现在使用关联数组进行了更多输入
        • 嗨@AlbertM 答案已更新...不是为了再次标记为您的问题的解决方案,而是为了让您对未来的实施有更多想法...祝您有美好的一天。
        【解决方案7】:

        这是从其中一个答案修改而来的,并允许使用关联数组作为可选参数以任何顺序添加参数

         function createUrl($host, $path, $argument = []){
           $optionalArgs = [
            'protocol'=>'http',
            'port'=>80];
          if( !is_array ($argument) ) return false;
          $argument = array_intersect_key($argument,$optionalArgs);
          $optionalArgs = array_merge($optionalArgs,$argument);
          extract($optionalArgs);
          return $protocol.'://'.$host.':'.$port.'/'.$path;
         } 
        
        
        
          //No arguments with function call
          echo createUrl ("www.example.com",'no-arguments'); 
          // returns http://www.example.com:80/no-arguments
        
          $argList=['port'=>9000];
          //using port argument only
          echo createUrl ("www.example.com",'one-args', $argList); 
          //returns http://www.example.com:9000/one-args
        
          //Use of both parameters as arguments. Order does not matter
          $argList2 = ['port'=>8080,'protocol'=>'ftp'];
          echo createUrl ("www.example.com",'two-args-no-order', $argList2); 
          //returns ftp://www.example.com:8080/two-args-no-order
        

        【讨论】:

          猜你喜欢
          • 2013-08-29
          • 2020-07-10
          • 2020-04-21
          • 1970-01-01
          • 1970-01-01
          • 2019-09-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多