douwuli4512 2014-06-13 21:52
浏览 706
已采纳

PHP函数有可选参数但允许null(和类似)值?

I'm aware that you can have PHP functions with optional arguments like so:

function do_something($argument = null) 
{
   // argument not provided
   if ($argument === null) 
      ........
}

Consider the case that null/false and other values are all valid arguments to my function. How can I determine whether an argument was provided or not?

do_something(null);            // argument provided
do_something(false);           // argument provided
do_something(0);               // argument provided
do_something("test");          // argument provided
do_something(new stdClass());  // argument provided
do_something();                // nothing provided

How can I detect the last case? I have thought about using func_num_args which would work in most cases but it doesn't work if I have several optional arguments.

Is there anything that solves this problem?

  • 写回答

4条回答 默认 最新

  • dougang8233 2014-06-13 22:00
    关注

    func_num_args() should work exactly as you want it to, because you might be assuming something that's actually not the case: You can't have optional arguments left out if they are in the middle of your arguments list.

    So let's look at this function:

    function test1 ($param1 = null, $param2 = null) {
       return func_num_args();
    }
    

    If I call that with different parameter combinations I get the following results:

    test1()              => 0
    test1(true)          => 1
    test1(true, true)    => 2
    

    There is just no way to call the function in a way where $param2 would be set while $param1 isn't. So you can map every possible output of func_num_args() to exactly one parameter configuration.

    In the example above you can rely on the fact that

    • if the return value is 1, $param2 definitely hasn't been set, while $param1 has been.
    • For 0 it's 100% sure that neither one has been given.
    • And, of course, if it's 2 both are there.

    What you actually would need are named parameters, as many other languages have them. PHP doesn't at the moment. NikiC actually wrote an RFC that suggests the addition of named parameters to PHP, but I think that's still way off in the future. You can check that out here: https://wiki.php.net/rfc/named_params

    As these are not yet available, here are a few workarounds you can try:

    Workaround 1

    If you really need to be able to have all the parameters optional, try a parameter array:

    function test1 (array $opts) {
        if (!isset($opts['opt1'])) { $opts['opt1'] = 'default1'; }
        if (!isset($opts['opt2'])) { $opts['opt2'] = 'default2'; }
    }
    

    Then you can call it like this:

    test1(array('opt2' => true))
    

    It would set the first parameter to "default1" while keeping the second. And there are definitely better and more elegant ways to do this (e.g. using an object instead), but the general idea is the same.

    Workaround 2

    You could also go with alias functions:

    function test ($param1, $patam2) { ... ]
    function testNoParam1 ($param2) {
        test("default1", $param2);
    }
    

    That at least makes it very easy to read, but of course you need to pick the right function depending on the parameters you have.

    Workaround 3

    By adding a lot of additional code you could get really fancy and use a FactoryObject:

    class FunctionExecutor {
        private $param1 = "default1";
        private $param2 = "default2";
    
        public function param1($val) {
           $this->param1 = $val;
           return $this;
        }
    
        public function param2($val) {
           $this->param2 = $val;
           return $this;
        }
    
        public function execute() {
           return yourFunction($this->param1, $this->param2);
        }
    }
    

    This could be used like this:

    $doSomething = new FunctionExecutor();
    $returnValue = $doSomething->param2(42)->execute();
    

    In this approach it would probably be a better idea to actually put your function into the object instead of defining it globally. Anyway...this is definitely a possibility, but not the most practical one. Just wanted to add it, because it has some benefits.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

悬赏问题

  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮
  • ¥15 ads仿真结果在圆图上是怎么读数的
  • ¥20 Cotex M3的调试和程序执行方式是什么样的?
  • ¥20 java项目连接sqlserver时报ssl相关错误
  • ¥15 一道python难题3
  • ¥15 牛顿斯科特系数表表示
  • ¥15 arduino 步进电机
  • ¥20 程序进入HardFault_Handler
  • ¥15 关于#python#的问题:自动化测试