给变量一个默认值的最好方法(模拟 Perl ||, ||= )

Posted

技术标签:

【中文标题】给变量一个默认值的最好方法(模拟 Perl ||, ||= )【英文标题】:Best way to give a variable a default value (simulate Perl ||, ||= ) 【发布时间】:2011-08-23 18:30:39 【问题描述】:

我喜欢在 Perl 中做这样的事情:如果 $bar 为空或未定义,$foo = $bar || $baz$baz 分配给 $foo。您还有$foo ||= $bletch,它只会在$foo 未定义或为空时将$bletch 分配给$foo

这种情况下的三元运算符既乏味又令人厌烦。 php 中肯定有一个简单、优雅的方法吗?

或者唯一的答案是使用 isset() 的自定义函数?

【问题讨论】:

相关Code Review:codereview.stackexchange.com/q/12722/31433 顺便说一句,具有所需功能的 Perl 运算符是 ////=,它们从 Perl v5.10.0 开始存在。原始的 ||||= 测试逻辑值,而不是定义性。 @Palec,为什么一个 4 年有 29 个赞的问题会被识别为一个 1 年有 6 个赞的问题的副本(它本身被标记为另一个问题的副本?)我认为保留这个问题很有价值,因为标题更通用(没有引用答案,即:isset())。 它们是清晰准确的重复。它承认我没有想太多应该是原始的,我正处于其他事情的中间,在两者之间建立联系是目标。收回我的 VTC。 完全重复,标记(IMO 错误)为另一个问题的重复:PHP shorthand for isset()? 【参考方案1】:

PHP 5.3 有一个简写 ?: 运算符:

$foo = $bar ?: $baz;

如果$bar不是一个空值(我不知道这在PHP中与Perl有何不同),则分配$baz,并且与Perl和旧版本的PHP相同:

$foo = $bar ? $bar : $baz;

但是 PHP 没有为此提供复合赋值运算符(也就是说,没有等效于 Perl 的 ||=)。

另外,如果没有设置$bar,PHP 会发出噪音,除非你关闭通知。 isset()empty() 之间也存在语义差异。如果变量不存在或设置为NULL,则前者返回false。后者在不存在或设置为0''falseNULL 时返回true。

【讨论】:

+1 为了向我介绍 5.3 的另一个重要功能,我错过了我的 RHEL5/PHP5.1.2 服务器。 我猜你的意思是The first returns,而不是倒数第二句中的The second 请注意,如果您的变量未定义,PHP 将发出有关它的通知。不幸的是,这不能替代$var = isset($var) ? $var : 'default value'; 它在答案中说......只是为任何浏览它的人再次指出它。 :-D 做 $var = @$var 是不是很糟糕?:'默认值';如果是这样,为什么?鉴于唯一的“错误”可能是 $var 未设置,并且我们不在乎 $var 是否未设置...【参考方案2】:

在 PHP 7 中,我们终于有办法优雅地做到这一点。它被称为Null coalescing operator。你可以这样使用它:

$name = $_GET['name'] ?? 'john doe';

这相当于

$name = isset($_GET['name']) ? $_GET['name']:'john doe';

【讨论】:

我认为spaceship operator 也有优点。 我以为马里亚诺在拉扯我们的腿,但不是的,这是 <=> 并且非常准确! 请注意,空合并运算符的行为与条件运算符不同,因为它特定于 null 值。例如,如果$_GET['name'] 设置为空字符串,第一行将返回一个空字符串,但我们可以使用$_GET['name'] ? $_GET['name'] : 'john doe' 返回“john doe”。 @Mariano 是的,但宇宙飞船操作员与这里有什么关系?【参考方案3】:

感谢所有精彩的答案!

对于其他来这里寻找可能替代方案的人,这里有一些功能可以帮助您摆脱这种乏味的事情。

function set_if_defined(&$var, $test)
    if (isset($test))
        $var = $test;
        return true;
     else 
        return false;
    


function set_unless_defined(&$var, $default_var)
    if (! isset($var))
        $var = $default_var;
        return true;
     else 
        return false;
    


function select_defined()
    $l = func_num_args();
    $a = func_get_args();
    for ($i=0; $i<$l; $i++)
        if ($a[$i]) return $a[$i];
    

例子:

// $foo ||= $bar;
set_unless_defined($foo, $bar);

//$foo = $baz || $bletch
$foo = select_defined($baz, $bletch);

我相信这些可以改进。

【讨论】:

【参考方案4】:

与旧 PHP 版本保持兼容的常见习惯用法是:

 $var = $bool   or   $var = "default";
 // If I use it, then only with excessive spaces for clarity.

这适用于可以在布尔上下文中评估的值。这里的好处是,如果变量未定义,它还可以为您提供调试 e_notice。

【讨论】:

如果$bool 未定义,通知是否与$bool ? $bool : "default" 一起发出? 当然,也一样。我假设 OP 指的是isset($var) ? $var : DEFAULT。但听起来他无论如何都想避开他们。【参考方案5】:

在早于 7.* 的 PHP 中,可以将 ?: 用于未定义的变量,该变量在本地使用 @ 抑制错误:

$foo = @$bar ?: $baz;

【讨论】:

【参考方案6】:

这是isset 案例的另一种好格式

isset($foo) || $foo= $bar;

另一种简单的方法,可以让您获得更多控制权,因为您可以添加更多条件并同时分配给另一个变量

$foo = (isset($oData['foo']))?$bar['foo']:'default value';

【讨论】:

【参考方案7】:

一个可能的解决方案:defaultFor( )

除非我们有工厂解决方案(这确实很烦人),否则我会推荐以下小帮手。它在大多数情况下都能胜任:


    function defaultFor(&$x,$default=null) 
        if(!isset($x)) $x = $default;
    

    //--------------------  Now you can do this: --------------

    defaultFor($a,"Jack");  // if $a is not set, it will be "Jack"
    defaultFor($x);         // no more notices for $x but keep it !isset

我希望这接近您想要实现的目标。如果您将它与不存在的变量一起使用,它不会给您任何通知,并且非常方便。当然它有一个缺点:默认值总是预先计算出来的,所以不要将它与任何重的作为第二个参数的东西一起使用,比如 file_get_contents 或其他东西。在这些情况下,最好使用 isseting。

【讨论】:

【参考方案8】:

我认为通常会做这样的事情:

$foo = $bar || $baz;

是个坏主意,除非 $bar$baz 都是布尔值。如果不是:

$bar = 10;
$baz = 11;

那么问题就变成了:是什么决定了事物的真假?大多数人可能会认为零是假的,而其他一切都是真的。但是对于某些语言(例如 Ruby),只有 falsenil 是错误的,这意味着 01 都是正确的。由于这种跨语言的歧义,我认为在这些情况下最好是明确的:

if ($bar !== 0) 
   $foo = $bar;
 else 
   $foo = $baz;

或:

$foo = $bar !== 0 ? $bar : $baz;

【讨论】:

以上是关于给变量一个默认值的最好方法(模拟 Perl ||, ||= )的主要内容,如果未能解决你的问题,请参考以下文章

在 Perl 中如何使用变量作为哈希键?

Perl 6 中的主题变量 $_

为变量分配默认值的最短方法?

Perl 将变量传递给子程序

在 Perl 中从数组中删除值的最佳方法是啥?

在 perl 中如何在不使用 XS 的情况下写入调用者的变量?