如果变量为空,则设置默认值
代码审查 | 2021-01-04 | 编程黑洞网 | | 339 人阅读
这是我一直在使用的模式,“如果变量为空,请设置默认值”,对于
$muffin
之类的变量,一切似乎都很好。但是在下面的实际示例中,此模式给了我一条超长的线条,让我有点闻起来。有没有更清洁的方法?
$newsItems[0]['image_url']= $newsItems[0]['image_url']=='' ? '/img/cat_placeholder.jpg' : $newsItems[0]['image_url'];
评论
从PHP 7.0开始,Langen的答案可能是最好的:$ newsItems [0] ['image_url'] = $ newsItems [0] ['image_url']? '/img/cat_placeholder.jpg'; php.net/manual/en/…
从PHP 7.4开始,有一个本机运算符-?? =
#1 楼
在处理您的问题之前,我想指出一下,您可能要使用
empty()
而不是与空字符串进行比较,并且如果您确实要与空字符串进行比较,请使用
===
运算符。
无论如何,默认初始化是许多语言中的实际问题。 C#甚至有一个??接线员解决这类问题!因此,让我们尝试使其更好地逐步改进您的代码。在多行代码上是个坏主意:那就是if语句的作用:
if (empty($newsItems[0]['image_url'])) {
$newsItems[0]['image_url'] = '/img/cat_placeholder.jpg';
}
这有两个原因,它更具可读性:语法更容易理解,但更多重要的是,不存在任何内容时,您会更容易看到您只是想要一个默认值。我们不需要将“ else”部分与三元运算符相混淆。 br />
$newsItems[0]['image_url'] = $newsItems[0]['image_url'] ?: 'img/cat_placeholder.jpg';
对其进行因子化!
如果只执行一次或两次,那么一切都很好,但是如果不想这样做将其分解为一个函数,因为您不会重复自己,对吧?简单的方法是:
function default_value($var, $default) {
return empty($var) ? $default : $var;
}
$newsItems[0]['image_url'] = default_value($newsItems[0]['image_url'], '/img/cat_placeholder.jpg');
(三元运算符在这里确实有意义,因为变量名短且条件的两个分支都有用。) br />但是,我们在调用
$newsItems[0]['image_url']
时正在查找
default_value
,这可能是未定义的,并且会引发错误/警告。如果这是一个问题(应该),请坚持使用第一个版本,或者查看另一个给出更可靠解决方案的答案,以将PHP代码存储为字符串的方式进行,因此无法进行语法检查。
还是太长了
如果我们不在乎警告/错误,我们可以做得更好吗?我们可以!我们已经两次写了变量名,但是通过引用传递可以在这里为我们提供帮助:
function default_value(&$var, $default) {
if (empty($var)) {
$var = $default;
}
}
default_value($newsItems[0]['image_url'], '/img/cat_placeholder.jpg');
它更短,并且更具声明性:您可以查看一堆
default_value
调用,并立即查看默认值。但是我们仍然有相同的警告/错误问题。
#2 楼
从这里开始:
自PHP 5.3起,可以省去
三元运算符的中间部分。如果expr1
的计算结果为TRUE,则表达式expr1?:expr3返回expr1,否则为expr3。 />
#3 楼
瞧瞧,PHP 7的空合并运算符的强大功能!由于明显的原因,它也被称为isset三元运算符。添加,如果存在且不为NULL,则返回其第一个操作数的结果,否则返回第二个操作数的结果。这意味着$_GET['mykey'] ?? ""
是完全安全的,不会举起E_NOTICE
。
它看起来像
$survey_answers = $_POST['survey_questions'] ?? null;
甚至可以链接。它将使用存在的第一个值并且不为null,请考虑以下因素:
#4 楼
extract()
函数也可以提供帮助。
它不适用于像您在此处使用的单个数组键,但在其他情况下可能很有用。
extract(array('foo'=>'bar'), EXTR_SKIP);
仅当尚未设置时,这会将
bar
分配给
$foo
作为默认值。如果已经设置了
$foo
,它将跳过它。您可以在数组中包含多个变量。
#5 楼
做到OOP风格
如果要进行OOP,也可以重新考虑是否使用普通数组。我想image_url
并不是新闻项的唯一属性,因此请将此数组结构转换为对象。此外,$newsItems
可能会更改为NewsItem
实例的数组。
/img/cat_placeholder.jpg
可能是新类NewsItem中属性image_url
的默认值。您的客户代码决定是要设置一个新值(例如,基于!empty()
),还是您的NewsItem
类具有用于属性image_url
的设置方法,该方法会在获取空字符串时自动设置默认值。
#6 楼
警告
请勿同时执行以下两项操作:
$array['index'] = $array['index'] ?: $default;
function default_value(&$var, $default) {
if (empty($var)) {
$var = $default;
}
}
default_value($array['index'], $default);
由于未定义的索引,两者都将引发错误(两次尝试获取如果未设置索引,则返回第一个值)。这是一件小事,但是即使您已报告错误并关闭了日志记录,在检查是否有任何报告错误的地方之前,也会引发错误,生成错误并在堆栈中传播错误。因此,只需执行可能会引发错误并导致性能下降的操作即可。
请记住这一点,因为这适用于所有错误类型(通知,警告等),并且在大型应用中很大。为避免这种情况,您必须使用不会对丢失的索引引发错误的函数,例如
isset($array['index'])
或
empty($array['index'])
,并且不要使用简化的三进制形式。 br />
function apply_default(Array &$array, $path, $default) {
// may need to be modified for your use-case
preg_match_all("/\[['\"]*([^'\"]+)['\"]*\]/im",$path,$matches);
if(count($matches[1]) > 0) {
$destinaion =& $array;
foreach ($matches[1] as $key) {
if (empty($destinaion[$key]) ) {
$destinaion[$key] = array();
}
$destinaion =& $destinaion[$key];
}
if(empty($destinaion)) {
$destinaion = $default;
return TRUE;
}
}
return FALSE;
}
$was_applied = apply_default($array,
"['with a really long name']['and multiple']['indexes']",
$default_value);
这不会引发错误,并且会在路径不存在的情况下创建路径。它也得益于将逻辑设置为在一个地方设置默认值,而不是在各处设置
if
。
如其他地方所述,另一种选择是: >
同样好,而且性能可能更好。如果该值为空,则应该允许使用者(无论是视图还是其他客户端(例如javascript))自行选择此选项。实际上,该模型的语义数据为空。处理方式应取决于消费者本身,即,如果要转到模板/视图,则应在显示期间处理条件。如果将其作为JSON发送,则客户端应该可以选择。
您正在询问样式,这可能是最重要的。最好的样式是,如果要向客户端提供数据,请不要伪造(而是记录可能的空响应)。
#7 楼
PHP 7.4添加了??=
,这正是您所需要的空合并分配运算符。
评论
\ $ \ begingroup \ $
此处介绍的后两个选项将引发错误,并且(因此)也会影响性能。不过,我不必提及性能,因为错误(警告,在这种情况下为未定义的索引)应该就足够了。即使报告/日志功能已关闭,解释器也注意到的事实对性能的影响要大于空值,并与if一起设置。坚持使用if,或使用下面的解决方案。
\ $ \ endgroup \ $
–迈克
2015年1月6日在21:39
\ $ \ begingroup \ $
谢谢。当然,这里的性能无关紧要,除非已证明该代码是瓶颈的一部分。
\ $ \ endgroup \ $
– Quentin Pradet
2015年1月7日在7:57
\ $ \ begingroup \ $
@MichaelJMulligan我的编辑看起来公平吗?
\ $ \ endgroup \ $
– Quentin Pradet
15年1月7日在8:03
\ $ \ begingroup \ $
@QuentinPradet,公平。至于句法检查,您能详细说明一下我的答案吗?我会感兴趣的。
\ $ \ endgroup \ $
–迈克
2015年1月7日15:45