PHP 中 C# 的空值合并运算符 (??)
Posted
技术标签:
【中文标题】PHP 中 C# 的空值合并运算符 (??)【英文标题】:C#'s null coalescing operator (??) in PHP 【发布时间】:2011-11-08 21:07:46 【问题描述】:php中是否有类似于C#的??
的三元运算符之类的?
C# 中的??
简洁而简短,但在 PHP 中您必须执行以下操作:
// This is absolutely okay except that $_REQUEST['test'] is kind of redundant.
echo isset($_REQUEST['test'])? $_REQUEST['test'] : 'hi';
// This is perfect! Shorter and cleaner, but only in this situation.
echo null? : 'replacement if empty';
// This line gives error when $_REQUEST['test'] is NOT set.
echo $_REQUEST['test']?: 'hi';
【问题讨论】:
?:
非常接近 ??
。事实上,?:
实际上比??
捕获更多类似空的情况; ??
专门用于 null
和 !Nullabe<T>.HasValue
。您听起来像是在寻找更像 javascript 的 ||
运算符的东西。就像?:
,但 JavaScript 不会抱怨引用未定义的键/成员——尽管如果您尝试引用未定义/空的键/成员,它会抛出错误,因此您只能进入一级。跨度>
@dpp,你为什么说someres
然后改成test
?
查看第 7 版。我们终于有了。
PHP 7 有这个功能。请查看wiki.php.net/rfc/isset_ternary
如前所述,这将出现在 PHP 7 中。在早期版本中,我认为这是错误抑制运算符的少数有效用例之一,例如echo @$_REQUEST['someres'] ?: 'hi';
抑制错误。
【参考方案1】:
PHP 7 添加了null coalescing operator:
// Fetches the value of $_GET['user'] and returns 'nobody'
// if it does not exist.
$username = $_GET['user'] ?? 'nobody';
// This is equivalent to:
$username = isset($_GET['user']) ? $_GET['user'] : 'nobody';
您还可以查看编写 PHP 三元运算符 ?: 的简短方法(仅限 PHP >=5.3)
// Example usage for: Short Ternary Operator
$action = $_POST['action'] ?: 'default';
// The above is identical to
$action = $_POST['action'] ? $_POST['action'] : 'default';
您与 C# 的比较是不公平的。 “在 PHP 中你必须做类似的事情” - 在 C# 中,如果你尝试访问不存在的数组/字典项,也会出现运行时错误。
【讨论】:
真的吗?那么,如果我正在访问一个不存在的数组元素呢?我也会得到错误,是的,这是有道理的。 @NullUserException:谢谢,我总是被这类短语卡住:-( 这是一个完全公平的说法。System.Linq
命名空间为数组等提供了扩展方法TSource Enumerable.ElementAtOrDefault<TSource>(this IEnumerable<TSource> source, int index)
。 IDictionary<TKey, TValue>
本身提供a method for this:bool IDictionary<TKey, TValue>.TryGetValue(TKey key, out TValue value)
。此方法返回两个值,因为 C# 更明确地区分 null
和未设置。如果您更愿意平等对待null
并取消设置,则可以轻松编写扩展方法。
@Zenexer:问题不在于方法,而在于运算符。感谢您无缘无故地投反对票。
@zerkms 在 Web 开发中,我们经常处理用户输入。甚至 API 也可能生成具有“可变数量的字段”的结构,我们仍然需要与它们集成。毕竟,isset
函数背后是有原因的。我的例子:empty($var)
但是不是很好。我应该写empty($var['key'])
之类的东西(假设确实定义了 $var,但我对'key' 的存在有疑问),但为了简洁起见,它被省略了。【参考方案2】:
??
在 C# 中是二进制的,而不是三进制的。它在 PHP 7 之前的 PHP 中没有等价物。
【讨论】:
在 PHP 5.3 中相当于?:
。例如。 test ?: ifNull
=== test ? test : ifNull
。换句话说,?:
在 PHP 中可以是二进制或三进制,因为中间操作数是可选的。
其实C#中的??
是三元的。它是三元运算的语法糖。它只是以二进制形式编写的。
@Zenexer:它是一个二元运算符,它不仅仅是语法糖——func() ?? otherfunc()
只调用一次func
,而func()!=null ? func() : otherfunc()
调用它两次,所以如果func
有副作用结果完全不同。
@aboveyou00 有趣;我不知道。【参考方案3】:
在 PHP 7 之前,没有。如果您需要涉及isset
,则使用的模式是isset($var) ? $var : null
。没有包含isset
特征的?:
运算符。
【讨论】:
这基本上使它在大多数情况下都没用。 :// 我还是找到了很多它的用例;它基本上相当于 PHP 的 Javascript 的||
运算符,非常方便。 :)【参考方案4】:
从 PHP 5.6 起不存在相同的运算符,但您可以创建一个行为相似的函数。
/**
* Returns the first entry that passes an isset() test.
*
* Each entry can either be a single value: $value, or an array-key pair:
* $array, $key. If all entries fail isset(), or no entries are passed,
* then first() will return null.
*
* $array must be an array that passes isset() on its own, or it will be
* treated as a standalone $value. $key must be a valid array key, or
* both $array and $key will be treated as standalone $value entries. To
* be considered a valid key, $key must pass:
*
* is_null($key) || is_string($key) || is_int($key) || is_float($key)
* || is_bool($key)
*
* If $value is an array, it must be the last entry, the following entry
* must be a valid array-key pair, or the following entry's $value must
* not be a valid $key. Otherwise, $value and the immediately following
* $value will be treated as an array-key pair's $array and $key,
* respectfully. See above for $key validity tests.
*/
function first(/* [(array $array, $key) | $value]... */)
$count = func_num_args();
for ($i = 0; $i < $count - 1; $i++)
$arg = func_get_arg($i);
if (!isset($arg))
continue;
if (is_array($arg))
$key = func_get_arg($i + 1);
if (is_null($key) || is_string($key) || is_int($key) || is_float($key) || is_bool($key))
if (isset($arg[$key]))
return $arg[$key];
$i++;
continue;
return $arg;
if ($i < $count)
return func_get_arg($i);
return null;
用法:
$option = first($option_override, $_REQUEST, 'option', $_SESSION, 'option', false);
这将尝试每个变量,直到找到满足 isset()
的变量:
$option_override
$_REQUEST['option']
$_SESSION['option']
false
如果没有 4,则默认为 null
。
注意:有一个使用引用的更简单的实现,但它具有setting the tested item to null if it doesn't already exist 的副作用。这个can be problematic 当数组的大小或真实性很重要时。
【讨论】:
没有回答 OP 的问题,即“这样的运营商是否存在”。此外,@LukLed 的回答(在此之后几个月发布)演示了类似的东西,而无需解构关联数组索引。 @benrifkah LukLed 的答案具有将指定键设置为 null 的负面影响:3v4l.org/9vmFR 如果您引用不存在的键,它将被创建。如果您使用不存在的数组,这尤其成问题:3v4l.org/sMsKD 我看到这个“第一个”函数的奇怪结果。想聊聊吗? chat.***.com/rooms/79985/… @benrifkah 抱歉回复晚了;现在就去那里。【参考方案5】:我使用函数。显然它不是运算符,但似乎比你的方法更干净:
function isset_or(&$check, $alternate = NULL)
return (isset($check)) ? $check : $alternate;
用法:
isset_or($_REQUEST['test'],'hi');
【讨论】:
为什么要传递$check
var 作为参考?
@AxelA.Grazx:我作为参考传递,因为如果它不作为参考发送,$_REQUEST['test']
值将在函数调用之前计算然后传递给函数。如果$REQUEST
数组没有这个元素,它将抛出Undefined index: test
错误。我想避免这种情况。
哦……现在我明白了……不错的方法。
这个答案应该更高——我一直在使用相同的方法,而且非常简洁。
这具有将选中键设置为 null 的负面影响:3v4l.org/9vmFR 这是一个特别成问题的情况:3v4l.org/sMsKD【参考方案6】:
Null Coalesce Operator, (??
) 已在PHP 7 中被接受和实施。它与short ternary operator (?:
) 的不同之处在于??
将抑制E_NOTICE
,否则在尝试访问没有密钥的数组时会发生这种情况。 RFC 中的第一个示例给出:
$username = $_GET['user'] ?? 'nobody';
// equivalent to: $username = isset($_GET['user']) ? $_GET['user'] : 'nobody';
注意??
运算符不需要手动应用isset
来防止E_NOTICE
。
【讨论】:
它实际上可以在isset()
的任何地方工作,因此它也适用于变量和属性。
另外,一个不错的功能是您可以链接它,例如:$_GET['user'] ?? $_SESSION['user'] ?? 'bob';
- 当它短路时,您甚至可以进行函数调用。另外,不像isset($foo) ? $foo : $bar
,如果它是一个函数调用(例如foo()[0]
),它不会计算两次。 :)
@AndreaFaulds 你应该说,不像普通的三元,你可以不用traumatic brain injury链接它。
嗯,你也可以使用短三元运算符?:
来做到这一点,这是一个不同的用例。以上是关于PHP 中 C# 的空值合并运算符 (??)的主要内容,如果未能解决你的问题,请参考以下文章