为什么是 'defined() ||define()' 定义常量的语法

Why 'defined() || define()' syntax in defining a constant

提问人:David Casillas 提问时间:8/10/2011 更新时间:2/1/2017 访问量:3282

问:

为什么在定义常量之前检查常量是否存在的方法:

defined('CONSTANT') || define('CONSTANT', somedefinition);

用于代替:

if !(defined('CONSTANT')) {
    define('CONSTANT', somedefinition);
}

在第一种方法中使用“or”而不是“||”有什么区别吗,我在书中都看到过。

PHP的

评论


答:

3赞 Pelshoff 8/10/2011 #1
defined('CONSTANT') || define('CONSTANT', somedefinition);

其实有点把戏。你看,||运算符仅在第一部分为 false 时执行表达式的第二部分:)这是编写相同功能代码的快速、简短的方法。

评论

3赞 deceze 8/10/2011
这里的关键词是短路评估
0赞 Joubarc 8/10/2011
有些语言倾向于使用它(perl),所以也许那些在 php 中这样做的人主要是出于习惯。知道是否有任何性能差异吗?
10赞 RichColours 8/10/2011 #2

由于 ||(在 C、Java、C#、php 中)被“短路”(如果第一个操作数为 true,则不计算第二个操作数,因为表达式已被计算为 true,无论第二个操作数是多少。

所以这是经典的C型“简洁”在行动。使用尽可能少的代码行,即使它的作用与更长手的东西完全相同。

所以它读作:如果定义(...),不要做define()位... 如果没有 defined(),请尝试计算 define() 位,在此过程中,它将定义常量。

评论

0赞 David Casillas 8/10/2011
所以语法无效,因为运算符没有“短路”?defined('CONSTANT') or define('CONSTANT', somedefinition);or
0赞 Mchl 8/10/2011
@David 卡西利亚斯 :是的。看看我的答案,解释 和 之间的区别||or
0赞 David Casillas 8/10/2011
@Mchl,我以为不是“短路”,只是优先级不同。or||
0赞 Matti Virkkunen 9/29/2017
据我所知,在 C 中使用代替 if 子句不是惯用的。事实上,它只是让我想起了PHP本身和Perl。||
5赞 Mchl 8/10/2011 #3

其他人已经回答了你问题的第一部分,所以我会选择后者:

就 vs 而言,在这种特定情况下没有区别。但是,运算符的优先级低于(赋值运算符),而具有更高的运算符。如果您想使用短路进行分配,这一点很重要。or||or=||

考虑:

$a = 2 or $b = 2;
var_dump($a);  // int(2)


$a = 3 || $b = 3;
var_dump($a);  // bool(true)

在第二个示例中,在 之前进行了评估。使用括号,它看起来像这样||=

$a = (3 || $b = 3);

而第一个

($a = 2) or ($b = 2);
1赞 Jonathan Falkner 2/1/2017 #4

所以我的假设是短路更快,因为 if 语句从定义中获取布尔值并使用 not 运算符翻转它,但为了彻底起见,这是我的基准测试:


PHP 5.6:

0.23026204109192 - Test1a:短路:第一个循环上的动态定义。
0.22264909744263 - Test1b:If 语句:第一个循环上的动态定义。
0.22433304786682 - Test2a:短路:运行测试前的静态定义。
0.22339177131653 - Test2b:If 语句:运行测试前的静态定义。
0.27459692955017 - Test3a:短路:从不定义变量。
0.28696393966675 - Test3b:If 语句:从不定义变量。

结论
太接近了,尽管如果从未定义变量,我们可以看到短路的速度明显提高。


PHP 7:

0.031289100646973 - Test1a:短路:第一个环路上的动态定义。
0.041652917861938 - Test1b:If 语句:第一个循环上的动态定义。
0.023349046707153 - Test2a:短路:运行测试前的静态定义。
0.052791118621826 - Test2b:If 语句:运行测试前的静态定义。
0.064755916595459 - Test3a:短路:从不定义变量。
0.056003093719482 - Test3b:If 语句:从不定义变量。

结论PHP 7 显然针对常量/定义变量的短路进行了优化,尽管如果从未定义常量,我们会看到相反的情况。这意味着对实际存在的常量的检查得到了显著改进,从而可以更轻松地查看 if 语句中添加的 not 运算符所需的额外处理。

总体结论

差异可以忽略不计(除非你要处理同一行代码的数百万次加载),所以使用对你和你的团队最有意义的方法。

另外,伙计,PHP7 在这些测试的性能方面抽 PHP 6.5!


法典:

$c1a=0;
$title1a = 'Test1a: Short circuit: Dynamic define on first loop.';
$c1b=0;
$title1b = 'Test1b: If Statement: Dynamic define on first loop.';

$c2a=0;
$title2a = 'Test2a: Short circuit: Static define before test is run.';
$c2b=0;
$title2b = 'Test2b: If Statement: Static define before test is run.';

$c3a=0;
$title3a = 'Test3a: Short circuit: Never define variable.';
$c3b=0;
$title3b = 'Test3b: If Statement: Never define variable.';

$start1a = microtime(true);
while ($c1a < 1000000) {
  ++$c1a;
  defined('TEST_CONST_1A') || define('TEST_CONST_1A', 'test');
}
$stop1a = microtime(true);

$start1b = microtime(true);
while ($c1b < 1000000) {
  ++$c1b;
  if (!defined('TEST_CONST_1B')) {
    define('TEST_CONST_1B', 'test');
  }
}
$stop1b = microtime(true);

define('TEST_CONST_2A', 'test');
$start2a = microtime(true);
while ($c2a < 1000000) {
  ++$c2a;
  defined('TEST_CONST_2A') || define('TEST_CONST_2A', 'test');
}
$stop2a = microtime(true);

define('TEST_CONST_2B', 'test');
$start2b = microtime(true);
while ($c2b < 1000000) {
  ++$c2b;
  if (!defined('TEST_CONST_2B')) {
    define('TEST_CONST_2B', 'test');
  }
}
$stop2b = microtime(true);

$start3a = microtime(true);
while ($c3a < 1000000) {
  ++$c3a;
  defined('TEST_CONST_3A') || $c3a;
}
$stop3a = microtime(true);

$start3b = microtime(true);
while ($c3b < 1000000) {
  ++$c3b;
  if (!defined('TEST_CONST_3B')) {
    $c3b;
  }
}
$stop3b = microtime(true);

print ($stop1a - $start1a) . ' - ' . $title1a . "\n";
print ($stop1b - $start1b) . ' - ' . $title1b . "\n";
print ($stop2a - $start2a) . ' - ' . $title2a . "\n";
print ($stop2b - $start2b) . ' - ' . $title2b . "\n";
print ($stop3a - $start3a) . ' - ' . $title3a . "\n";
print ($stop3b - $start3b) . ' - ' . $title3b . "\n";