Is there any difference in PHP between while(true)
and for(;;)
besides syntax and readability?
Ok, so first off, let me say this: Use while(true)
, as it gives the most semantic meaning. You need to parse for (;;)
as it's not something you see often.
With that said, let's analyze:
Opcodes
The code
while(true) {
break;
}
echo "hi!";
Compiles down to the opcodes:
0: JMPZ(true, 3)
1: BRK(1, 3)
2: JMP(0)
3: ECHO("hi!")
So basically, it does a check if "true", and if not, jumps to the 4th opcode which is the echo opcode). Then it breaks (which is really just a static jump to the 4th opcode). Then the end of the loop would be an unconditional jump back to the original check
Compare that to:
for (;;) {
break;
}
echo "hi!";
Compiles down to:
0: JMPZNZ(true, 2, 4)
1: JMP(0)
2: BRK(1, 4)
3: JMP(1)
4: ECHO("hi!")
So we can immediately see that there's an extra opcode in the for(;;)
version.
Opcode Definitions
JMPZ(condition, position)
This opcode jumps if the condition is false
. If it is true
, it does nothing but advance one opcode.
JMPZNZ(condition, pos1, pos2)
This opcode jumps to pos1
if the condition is true, and pos2
if the condition is false.
JMP(position)
This opcode always jumps to the opcode at the specified position.
BRK(level, position)
This breaks level
levels to the opcode at position
ECHO(string)
Outputs the string
Are They The Same
Well, looking at the opcodes, it's clear that they are not identical. They are ==
, but not ===
. The while(true)
loop does a conditional jump followed by code followed by an unconditional jump. The for(;;)
loop does a conditional jump, followed by code, followed by an unconditional jump, followed by another unconditional jump. So it does an extra jump.
Opcache
In 5.5, the Optimizer portion of opcache will optimize static conditional jumps.
So that means the while(true)
code will optimize down to:
0: BRK(1, 2)
1: JMP(0)
2: ECHO("hi!")
And for(;;)
loop becomes:
0: BRK(1, 2)
1: JMP(0)
2: ECHO("hi!")
This is because the optimizer will find and optimize out jump-chains. So if you're using 5.5's built-in opcache, they will be identical...
Caution
This is a complete and utter micro-optimization to base a decision on. Use the readable one. Don't use one based on performance. The difference is there, but it's trivial.
JMP(1)
as the first instruction in the optimized while
version? Isn’t that effectively a no-op? Why doesn’t it get optimized away? –
Oxidimetry JMP(2); JMP(0);
will get optimized down to JMP(2);
, but I can't tell immediately if it will be optimized further to a NOP... –
Unesco while(true)
should be preferred. –
Whereof (;;)
as a crying face, because why are you writing infinite loops? That makes me sad. –
Incongruous for (;;)
" part -- it's actually quite often used in C instead of while (1)
because linters complain less about the for
variant [citation needed] –
Chrysoprase foreach ($a as $b) {}
requires understanding of what $a
may be (and its behaviors). Which is not semantic, but pragmatic meaning. while(true)
is purely semantic, as nothing but the grammar presented in front of you is needed to decipher the meaning. –
Unesco © 2022 - 2024 — McMap. All rights reserved.
while(true)
– Lapsewhile(1)
– Puccoonfor(;;)
is even shorter (by one character). The length doesn't matter, but readability does. – Wentzwhile(true)
orfor(;;)
based on how many opcodes are emitted? In PHP? Isn't that somewhat, just a little bit of a micro-optimization? – Raybinwhile(true)
– Nethermost