开发者

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

开发者 https://www.devze.com 2023-03-27 15:21 出处:网络
Why is this method of checking if a constant exist before defining it: defined(\'CONSTANT\') || define(\'CONSTANT\', somedefinition);

Why is this method of checking if a constant exist before defining it:

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

used instead of:

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

I开发者_如何学运维s there any difference in using 'or' instead of '||' in the first method, I have seen both in books.


Due to the || being (in C, Java, C#, php) being "short-circuited" (if the first operand is true, the second is not evaluated because the expression has already been evaluated to be true, no matter what the second is.

So this is classic C-style "brevity" in action. Use as fewer lines of code as possible, even though its doing exactly the same as something more longhand.

So it reads: if defined(...), don't do the define() bit... if not defined(), do try to evaluate the define() bit and in the process, it'll define the constant.


Others have answered first part of your question, so I'll take the latter:

As far as or vs || is concerned there is no difference in this specific case. However, or has lower operator precedence than = (assignment operator), while || has higher. This is significant, if you want to use short-circuiting to do assignment.

Consider:

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


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

In second example, || got evaluated before =. Using parentheses it would look like this

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

while the first one

($a = 2) or ($b = 2);


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

Is actually a bit of a trick. You see, the || operator only executes the second part of the expression when the first part is false :) It's a quick, short way to write the same functioning code.


So my assumption is the short circuit is faster, since the if statement is taking the boolean value from defined and flipping it using a not operator, but just to be thorough, here's my benchmark testing:


PHP 5.6:

0.23026204109192 - Test1a: Short circuit: Dynamic define on first loop.
0.22264909744263 - Test1b: If Statement: Dynamic define on first loop.
0.22433304786682 - Test2a: Short circuit: Static define before test is run.
0.22339177131653 - Test2b: If Statement: Static define before test is run.
0.27459692955017 - Test3a: Short circuit: Never define variable.
0.28696393966675 - Test3b: If Statement: Never define variable.

Conclusion
Too close to tell, though we can see a noticeable speed improvement for short circuit if the variable is never defined.


PHP 7:

0.031289100646973 - Test1a: Short circuit: Dynamic define on first loop.
0.041652917861938 - Test1b: If Statement: Dynamic define on first loop.
0.023349046707153 - Test2a: Short circuit: Static define before test is run.
0.052791118621826 - Test2b: If Statement: Static define before test is run.
0.064755916595459 - Test3a: Short circuit: Never define variable.
0.056003093719482 - Test3b: If Statement: Never define variable.

Conclusion PHP 7 clearly optimizes for the short circuit in the case of constants/defined variables, though we see the opposite if the constant is never defined. This implies that checking for constants that actually exist has been dramatically improved, making it easier to see the extra processing that is required by the added not operator in the if statement.

Overall Conclusion

The difference is negligible (unless you're getting into the millions of loads of the same line of code) so use whatever makes the most sense for you and your team.

Also, man, PHP7 smokes PHP 6.5 in terms of performance of these tests!


Code:

$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";
0

精彩评论

暂无评论...
验证码 换一张
取 消