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

115

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

假设我有以下代码:

function getData($name, $limit = '50', $page = '1') {
    ...
}
我该如何调用这个函数,使得中间的参数采用默认值(即 '50')?
getData('some name', '', '23');

以上的代码是否正确?我似乎无法让它工作。


1
@Chuck,你具体是在寻找什么?比如一个解决方法或者实现这个功能的类等等? - Rizier123
@Rizier123 我想问一下当前版本的PHP是否支持跳过参数(就像其他语言一样)。当前的答案可能已经过时了。从赏金描述来看:“当前的答案已经五年了。当前版本的PHP是否有所改变?” - Chuck Le Butt
1
@Chuck 那么答案可能是:没有任何改变;如果没有解决方法/代码,你将无法获得所需的功能。 - Rizier123
所有这里的答案都似乎假定你对被调用的函数有控制权。如果那个函数是库或框架的一部分,你只能在需要第三个参数时为参数2指定某些内容。唯一的选择是查看函数源代码并复制默认值。 - Snapey
无法跳过它,但是您可以使用ReflectionFunction传递默认参数。我在类似的问题中发布了答案 - David
可能是在函数中使用默认参数的重复问题。 - David
21个回答

59

您的帖子是正确的。

不幸的是,如果您需要在参数列表的最后使用可选参数,则必须指定该参数之前的所有内容。通常,如果您想混合和匹配,可以将它们的默认值设置为''null,如果它们是这个默认值,则不在函数内使用。


1
你能提供一个例子吗? - i am me
2
getData 函数的开头,@iamme 执行 $limit = is_numeric($limit) ? $limit : '50'; - Kamafeather
1
2022年使用PHP 8.x出现错误答案。 - Picard
1
这个的PHP文档在这里,而这里已经有一个Stackoverflow上的答案了。 - Picard
@Picard,2022年的正确答案是什么? - Oleksandr IY
显示剩余2条评论

44

不,不能用这种方式跳过参数。您只能在参数列表末尾省略传递参数

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


2
PHP支持默认参数值。但是这些参数必须在列表末尾。 - Cristik
1
你可以在PHP文档中找到示例。 - Cristik
2
白痴。让我很生气。如果你不喜欢别人请求的功能,就别使用它。互联网有时是最糟糕的。 - Lee Saxon
1
2022年使用PHP 8.x出现错误答案。 - Picard
2
当然可以!这里是 PHP 的文档 here,而且 here 已经有一个 Stackoverflow 上的答案了... 还有一个在下面。 - Picard
显示剩余4条评论

41

除了指定像falsenull这样的默认值之外,没有其他方法可以“跳过”参数。

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

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

正如评论中所 eloquently 说的那样,这是使用数组来模拟命名参数。

这提供了终极的灵活性,但在某些情况下可能不需要。至少,您可以将您认为大多数情况下不被期望的任何内容移动到参数列表的末尾。


2
我会将“something like this”识别为“使用数组模拟命名参数”,顺便说一句。 :) - chaos
3
尽管更加灵活,但你需要记住应该/可以设置的参数(因为它们不在签名中)。因此最终它可能并不像看起来那么有用,但当然这取决于背景。 - Felix Kling
那么在这种情况下,最佳实践是什么? - Adam Grant
1
2022年使用PHP 8.x出现错误答案。 - Picard

10

这个功能是在PHP8.0中实现的

PHP 8引入了命名参数

它:

允许任意跳过默认值

参考文档

使用此功能不需要进行任何更改:

让我们使用OP的函数 function getData($name, $limit = '50', $page = '1')

用法

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

原生函数也将使用此功能

htmlspecialchars($string, double_encode: false);
// Same as
htmlspecialchars($string, ENT_COMPAT | ENT_HTML401, 'UTF-8', false);

Netbeans IDE 12.3支持的功能

除了对命名参数的代码补全外,该功能得到支持,看起来更好 ;)

输入图像描述


7

关于跳过可选参数,没有任何变化,但为了正确的语法和能够指定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('某个名称',NULL,'23');以后任何调用该函数的人都不需要每次都记住默认值或为它们声明的常量。

1
你可能想要使用严格比较($limit === null)。 - roelleor

5
简单回答是“不行”。但为什么在重新排列参数时可以实现这个目的呢?
你的做法是“错误使用默认函数参数”,并且不会按照你的预期工作。
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(空),如果未定义的话。

这是最佳答案,因为它提供了清晰明了的语法解释!谢谢! - Christian

2

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

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

您可以添加所需的任意数量的参数,无需定义它们。当您调用函数时,将参数放置在以下位置:

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

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

如果有任何参数被跳过,你需要选择默认参数,以保险起见。

(在默认参数为''或类似情况下选择null,或反之亦然,会让你陷入麻烦...)


1
这是一个有一些技术能力回答的老问题,但它呼唤着PHP中的现代设计模式:面向对象编程。不要注入一系列原始标量数据类型,考虑使用一个“注入对象”,其中包含函数所需的所有数据。注入对象可能具有属性验证程序等。如果实例化和注入数据到注入对象无法通过所有验证,则代码可以立即抛出异常,应用程序可以避免处理潜在不完整的数据的尴尬过程。我们可以对注入对象进行类型提示以在部署之前捕获错误。一些想法在这篇文章中总结了几年。http://php.net/manual/en/language.types.intro.php

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接