PHP函数中的可选参数,无需考虑顺序

时间:2018-08-28 19:37:07

标签: php

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

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

我正在寻找一种不太冗长的解决方案,该解决方案使我可以仅传递与默认值不同的参数,而无需考虑函数声明中的顺序。

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

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

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

是否可以通过任何方式传递第二个可选参数($ port)而不传递$ protocol,它将“自动”填写$ protocol的默认值,即

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

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

7 个答案:

答案 0 :(得分: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

答案 1 :(得分:3)

在这种状态下,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

答案 2 :(得分:2)

嗯,这应该可行:

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;
}

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

答案 3 :(得分:1)

您可以将其重构为使用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);

答案 4 :(得分:0)

您的问题中有答复,您可以像这样声明函数

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

然后您使用

调用函数
myFunc($arg1, $arg2);

答案 5 :(得分:0)

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
}

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

PS。 Laravel框架中经常使用这种方法。从那里我得到了灵感。

答案 6 :(得分:0)

这是对答案之一的修改,它允许使用关联数组将可选参数以任意顺序添加参数

 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