如何在函数调用中跳过可选参数?


94

好的,我完全忘记了如何跳过PHP中的参数。

可以说我有:

function getData($name, $limit = '50', $page = '1') {
    ...
}

我将如何调用此函数,以使中间参数采用默认值(即“ 50”)?

getData('some name', '', '23');

以上正确吗?我似乎无法使它正常工作。


1
@Chuck您到底在找什么?像变通办法或类来实现此目标或...?
Rizier123

@ Rizier123我要询问当前版本的PHP是否支持跳过参数(就像其他语言一样)。当前答案可能已过时。从赏金的描述中:“当前答案已有五年历史了。最新版本的PHP会改变一切吗?”
Chuck Le Butt 2015年

1
@Chuck然后答案可能是:什么都没有改变;没有解决方法/代码,您将无法获得功能。
Rizier123

这里的所有答案似乎都假设您可以控制要调用的函数。如果该函数是库或框架的一部分,则您别无选择,如果需要参数3,则必须为参数2指定某些内容。唯一的选择是在函数的源代码中查找并复制默认值。
Snapey '17

无法跳过它,但是您可以使用传递默认参数ReflectionFunction。我在类似的问题中发布了该答案
戴维(David)

Answers:


55

您的帖子是正确的。

不幸的是,如果您需要在参数列表的最后使用可选参数,则必须指定直到最后一个参数为止的所有内容。通常,如果要混合匹配,请给它们提供默认值''null,如果它们是默认值,则不要在函数内使用它们。


1
你能举个例子吗?
我是我

2
@iamme $limit = is_numeric($limit) ? $limit : '50';getData函数的开头执行
Kamafeather

40

除了指定默认值(例如false或)外,无法“跳过”参数null

由于PHP在此方面缺少一些语法糖,因此您经常会看到类似以下的内容:

checkbox_field(array(
    'name' => 'some name',
    ....
));

正如评论中雄辩地说的那样,它使用数组来模拟命名参数。

这提供了最大的灵活性,但在某些情况下可能不需要。至少,您可以将大多数情况下无法想到的内容移至参数列表的末尾。


2
我将“类似的东西”标识为“使用数组来模仿命名的参数”,FWIW。:)
混乱

3
尽管更加灵活,但是您必须记住您应该/可以设置的参数(因为它们不在签名中)。因此,最终它可能并不像看起来那样有用,但这当然取决于上下文。
Felix Kling 2010年

那么,在这种情况下的最佳实践是什么?
亚当·格兰特

39

否,无法以这种方式跳过参数。当传递的参数位于参数列表的末尾时,可以省略传递的参数。

对此有一个正式建议:https : //wiki.php.net/rfc/skipparams,但被拒绝了。提案页面链接到有关此主题的其他SO问题。


那么PHP函数如何具有更多/更少参数的可选项?
我是我

2
PHP支持默认参数值。但是这些参数必须在列表的末尾。
Cristik

1
您可以在PHP文档中
Cristik

2
混蛋 让我生气。如果您不喜欢别人要求的功能,那就不要使用它。互联网有时是最糟糕的。
李撒克逊人

@LeeSaxon的问题是可读性和可移植性。1)如果有人决定跳过参数,而某人的调试代码却错过了这一事实,则会引起极大的混乱。2)如果不进行大修,新代码将无法在旧版本上运行,并且出错的机会非常高。
Mark Walsh

6

能够跳过可选参数的方法没有任何改变,但是对于正确的语法以及能够为我想跳过的参数指定NULL,我将这样做:

define('DEFAULT_DATA_LIMIT', '50');
define('DEFAULT_DATA_PAGE', '1');

/**
 * getData
 * get a page of data 
 *
 * Parameters:
 *     name - (required) the name of data to obtain
 *     limit - (optional) send NULL to get the default limit: 50
 *     page - (optional) send NULL to get the default page: 1
 * Returns:
 *     a page of data as an array
 */

function getData($name, $limit = NULL, $page = NULL) {
    $limit = ($limit===NULL) ? DEFAULT_DATA_LIMIT : $limit;
    $page = ($page===NULL) ? DEFAULT_DATA_PAGE : $page;
    ...
}

因此可以这样getData('some name',NULL,'23');调用:并且将来调用该函数的任何人都不必记住每次的默认值或为它们声明的常量。


1
您可能想要严格比较($ limit === null)
roelleor

4

简单的答案是“ 否”。但是,为什么在重新排列参数时跳过此操作呢?

您的代码是“ 默认函数参数的不正确用法 ”,将无法正常使用。

PHP文档的附带说明:

使用默认参数时,任何默认值都应位于所有非默认参数的右侧;否则,事情将无法按预期进行。

考虑以下:

function getData($name, $limit = '50', $page = '1') {
    return "Select * FROM books WHERE name = $name AND page = $page limit $limit";
}

echo getData('some name', '', '23');   // won't work as expected

输出将是:

"Select * FROM books WHERE name = some name AND page = 23 limit"

默认函数参数的正确用法应如下所示:

function getData($name, $page = '1', $limit = '50') {
    return "Select * FROM books WHERE name = $name AND page = $page limit $limit";
}

echo getData('some name', '23');  // works as expected

输出将是:

"Select * FROM books WHERE name = some name AND page = 23 limit 50"

将默认值放在非默认值之后的右边,以确保如果未定义/给出该值,它将始终重新调整该变量的默认值。这是参考链接,这些示例来自何处。

编辑:将其设置null为其他人建议的设置可能会起作用,这是另一种选择,但可能无法满足您的需求。如果未定义,它将始终将默认值设置为null。


这是最好的答案,因为它提供了清晰说明的语法解释!谢谢!
基督教徒

2

为了安全起见,对于跳过的任何参数(必须),请使用默认参数。

(如果将默认参数设置为”或类似参数,则将其设置为null,反之亦然,这会使您陷入麻烦...)


2

如上所述,您将无法跳过参数。我已写出此答案以提供一些附录,该附录太大而无法在评论中放置。

@Frank Nocke 建议使用默认参数调用该函数,例如

function a($b=0, $c=NULL, $d=''){ //...

你应该使用

$var = a(0, NULL, 'ddd'); 

在功能上与省略前两个($b$c)参数相同。

尚不清楚哪些是默认值(0键入以提供默认值,还是重要?)。

当默认值可以由函数(或方法)作者更改时,还存在默认值问题连接到外部(或内置)函数的危险。因此,如果您不更改程序中的调用,则可能会无意中更改其行为。

一些解决方法可能是定义一些全局常量,例如DEFAULT_A_B,将其设为“函数A的B参数的默认值”和“忽略”参数,如下所示:

$var = a(DEFAULT_A_B, DEFAULT_A_C, 'ddd');

对于类,如果定义类常量,则更容易,更优雅,因为它们是全局范围的一部分,例如。

class MyObjectClass {
  const DEFAULT_A_B = 0;

  function a($b = self::DEFAULT_A_B){
    // method body
  }
} 
$obj = new MyObjectClass();
$var = $obj->a(MyObjectClass::DEFAULT_A_B); //etc.

请注意,此默认常量在整个代码中仅定义了一次(即使在方法声明中也没有值),因此,如果发生某些意外更改,您将始终为函数/方法提供正确的默认值。

该解决方案的清晰度当然不是提供原始默认值(比如更好的NULL0等等),这没什么好说的读者。

(我同意打电话$var = a(,,'ddd');是最好的选择)


2

您不能跳过参数,但是可以使用数组参数,并且只需要定义1个参数,即参数数组。

function myfunction($array_param)
{
    echo $array_param['name'];
    echo $array_param['age'];
    .............
}

您可以添加所需的任意多个参数,而无需定义它们。调用函数时,您可以像下面这样放置参数:

myfunction(array("name" => "Bob","age" => "18", .........));

0

正如其他人已经说过的那样,如果不在函数中添加任何代码行,PHP便无法实现您想要的功能。

但是您可以将这段代码放在函数的顶部,以获取功能:

foreach((new ReflectionFunction(debug_backtrace()[0]["function"]))->getParameters() as $param) {
    if(empty(${$param->getName()}) && $param->isOptional())
        ${$param->getName()} = $param->getDefaultValue();
}

因此,基本上,debug_backtrace()我得到了放置此代码的函数名称,然后创建一个新ReflectionFunction对象并遍历所有函数参数。

在循环中,我只是检查function参数是否为empty()AND,参数是否为“可选”(意味着它具有默认值)。如果是,我只是将默认值分配给参数。

Demo


0

将限制设置为空

function getData($name, $limit = null, $page = '1') {
    ...
}

并调用该功能

getData('some name', null, '23');

如果要设置限制,可以将其作为参数传递

getData('some name', 50, '23');

0

如前所述,什么都没有改变。但是要注意,过多的参数(尤其是可选参数)是代码异味的有力指标。

也许您的功能做得太多:

// first build context
$dataFetcher->setPage(1);
// $dataFetcher->setPageSize(50); // not used here
// then do the job
$dataFetcher->getData('some name');

一些参数可以按逻辑分组:

$pagination = new Pagination(1 /*, 50*/);
getData('some name', $pagination);
// Java coders will probably be familiar with this form:
getData('some name', new Pagination(1));

最后,您总是可以引入一个临时参数对象

$param = new GetDataParameter();
$param->setPage(1);
// $param->setPageSize(50); // not used here
getData($param);

(这只是不太正式的参数数组技术的美化版本)

有时,使参数成为可选参数的根本原因是错误的。在这个例子中,$page真的是可选的吗?保存几个字符真的有区别吗?

// dubious
// it is not obvious at first sight that a parameterless call to "getData()"
// returns only one page of data
function getData($page = 1);

// this makes more sense
function log($message, $timestamp = null /* current time by default */);

0

此代码段:

    函数getData($ name,$ options){
       $默认=数组(
            '限制'=> 50,
            '页面'=> 2,
        );
        $ args = array_merge($ default,$ options);
        print_r($ args);
    }

    getData('foo',array());
    getData('foo',array('limit'=> 2));
    getData('foo',array('limit'=> 10,'page'=> 10));

答案是:

     数组
    (
        [限制] => 50
        [页面] => 2
    )
    数组
    (
        [限制] => 2
        [页面] => 2
    )
    数组
    (
        [限制] => 10
        [页面] => 10
    )


2
真好 但稍作解释会有所帮助。
showdev

很好的答案,但是如果您要省略可选参数,请执行以下操作:function getData($ name,$ args = array()){$ defaults = array('limit':=> 50,'page'=> 2) ; $ args = array_merge($ defaults,$ args); 现在可以只使用第一个参数来调用此函数:getData('foo');
EchoSin

0

这就是我要做的:

<?php

    function getData($name, $limit = '', $page = '1') {
            $limit = (EMPTY($limit)) ? 50 : $limit;
            $output = "name=$name&limit=$limit&page=$page";
            return $output;
    }

     echo getData('table');

    /* output name=table&limit=50&page=1 */

     echo getData('table',20);

    /* name=table&limit=20&page=1 */

    echo getData('table','',5);

    /* output name=table&limit=50&page=5 */

    function getData2($name, $limit = NULL, $page = '1') {
            $limit = (ISSET($limit)) ? $limit : 50;
            $output = "name=$name&limit=$limit&page=$page";
            return $output;
    }

    echo getData2('table');

    // /* output name=table&limit=50&page=1 */

    echo getData2('table',20);

    /* output name=table&limit=20&page=1 */

    echo getData2('table',NULL,3);

    /* output name=table&limit=50&page=3 */

?>

希望这会帮助某人


0

这是一个古老的问题,提供了许多技术胜任的答案,但它呼唤着PHP中的一种现代设计模式:面向对象编程。与其注入原始标量数据类型的集合,不如考虑使用包含函数所需的所有数据的“注入对象”。 http://php.net/manual/zh/language.types.intro.php

注入的对象可能具有属性验证例程等。如果将数据的实例化和注入到注入的对象中无法通过所有验证,则代码可以立即引发异常,并且应用程序可以避免笨拙的处理过程可能包含不完整的数据。

我们可以键入提示以在部署之前捕获注入的对象以发现错误。几年前的这篇文章中总结了一些想法。

https://www.experts-exchange.com/articles/18409/Using-Named-Parameters-in-PHP-Function-Calls.html


0

我必须使用可选参数创建一个Factory,我的解决方法是使用空合并运算符:

public static function make(
    string $first_name = null,
    string $last_name = null,
    string $email = null,
    string $subject = null,
    string $message = null
) {
    $first_name = $first_name ?? 'First';
    $last_name  = $last_name ?? 'Last';
    $email      = $email ?? 'foo@bar.com';
    $subject    = $subject ?? 'Some subject';
    $message    = $message ?? 'Some message';
}

用法:

$factory1 = Factory::make('First Name Override');
$factory2 = Factory::make(null, 'Last Name Override');
$factory3 = Factory::make(null, null, null, null 'Message Override');

这不是最漂亮的东西,但可能是在工厂中进行测试的好模式。



-2

您不能在函数调用中跳过中间参数。但是,您可以解决此问题:

function_call('1', '2', '3'); // Pass with parameter.
function_call('1', null, '3'); // Pass without parameter.

功能:

function function_call($a, $b='50', $c){
    if(isset($b)){
        echo $b;
    }
    else{
        echo '50';
    }
}

我不确定您为什么要投反对票,除了$ c还需要一个默认值(在可选参数之后不能有任何必需的参数)。
Frank Forte

-2

正如@IbrahimLawal指出的那样。最佳做法是将它们设置为null值。只需检查传递的值null是否使用了您定义的默认值即可。

<?php
define('DEFAULT_LIMIT', 50);
define('DEFAULT_PAGE', 1);

function getData($name, $limit = null, $page = null) {
    $limit = is_null($limit) ? DEFAULT_LIMIT : $limit;
    $page = is_null($page) ? DEFAULT_PAGE : $page;
    ...
}
?>

希望这可以帮助。


您只需复制响应即可。相反,您可能对此有评论或评论。
Ibrahim Lawal

-6
getData('some name');

只是不要通过它们,默认值将被接受

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.