PHP 7.2's "switch" optimisations
PHP 7.2 is around the corner soon, and comes with many optimisations. Many new optimisations are implemented in opcache, but some others are implemented in PHP itself. One optimisation that falls in the latter category is an optimisation of the switch/case construct.
Before PHP 7.2, PHP considers each case statement in order. Let's say we have the following (trivial code):
<?php
$cc = "no";
switch ( $cc )
{
case 'de': echo "DEUTSCH"; break;
case 'en': echo "English"; break;
case 'nl': echo "Nederlands"; break;
case 'no': echo "Norsk"; break;
default:
echo "unknown"; break;
}
?>
The PHP interpreter approaches the executing of this switch/case structure as if it was written like:
<?php
$cc = "no";
if ($cc == 'de') {
echo "DEUTSCH";
} else if ($cc == 'en') {
echo "English";
} else if ($cc == 'nl') {
echo "Nederlands";
} else if ($cc == 'no') {
echo "Norsk";
} else {
echo "unknown"; break;
}
?>
Yup, it really compares $cc variable to each case statement one by one. Which means that if your most commonly used switch case is further down the list, you end up wasting valuable CPU code.
With vld we can represent this in a graph. For each case statement, the graph shows that the interpreter can either go left or right, just as it was executing multiple if statements in sequence:
PHP 7.2 introduces an optimisation that converts this sequence of if statements into a jump table if all the case statements are either integers or strings. If we look at the pseudo code (PHP does not support variable labels with goto), we get something like:
<?php
$cc = "no";
$_table = [ "de" => 1, "en" => 2, "nl" => 3, "no" => 4 ];
if (gettype($cc) == 'string') {
if (array_key_exists($cc, $_table)) {
goto "jmp_{$_table[$cc]}";
} else {
goto jmp_default;
}
} else {
/* do original if/else if/else sequence */
}
jmp_1: echo "DEUTSCH"; goto end;
jmp_2: echo "English"; goto end;
jmp_3: echo "Nederlands"; goto end;
jmp_4: echo "Norsk"; goto end;
jmp_default: echo "unknown";
end:
?>
This example shows that as long as $cc is a string, it will use the jump table $_table to jump (with goto) to the immediate code representing the case statement. If $cc is not a string, it will have to do the usual if/else if/else dance. In this case, it will eventually end up on the default case.
Looking at the graph generated by vld for this optimised construct, we see this new structure as well:
Especially with big switch/case structures this is a welcome optimisation!
However…
Xdebug implements code coverage gathering functionality. This can be used with PHP_CodeCoverage to see which parts of your code, which branches, and which paths are covered while executing your tests. In order for Xdebug to figure out the branches and paths, it has to follow PHP's internal opcode structures to see where jump instructions happen. I had to add support for this new switch/case optimisation to make this work again. This has now been done, and is part of Xdebug's master branch. This branch will soon become the first beta release of Xdebug 2.6 which will provide support for PHP 7.2.
Comments
The goto jmp_5; → jmp_5; is not defined
Thank you for sharing. Quite interesting - even for those in older versions of PHP!
That`s nice to know. I will keep that in mind. Thanks for sharing with us!
- Is it strict ? eg switch($num) {
-
case 1: echo 'its a num'; break; case '1': echo 'its a string': break;
}
Yes, it is strict. If there are mixed types in case statements, it won't create a jump table at all, and fall back to the original PHP 7.1 behaviour.
Life Line
Updated a waste_basket
Created 11 benches, 2 life_rings, and 3 other objects; Updated 8 benches and a waste_basket; Deleted a bench and a log; Confirmed a cafe
I walked 7.8km in 1h52m27s
Tomorrow we have elections in the UK!
Lots of local authorities, all London Councils, the Welsh Senedd, and the Scottish Parliament.
Don't forget to vote if you have the right.
I get to vote for myself again 😎.
Benches, and corrections for the QE II Gardens
Addresses on College Road
Created 2 main entrances and an entrance; Updated an entrance, a residential building, and a house building
Created an apartments building and a main entrance
I walked 9.5km in 2h21m10s
Created a waste_basket
I walked 6.6km in 1h13m23s
On my walk from Aylesbury to Princes Risborough I spotted a few new bird species. I didn't get all the best photos though!
A Common Buzzard, a Yellow Wagtail, a Greater White throat, and a Green Woodpecker.
#photography #Birds #BirdPhotogaphy #BirdsOfMastodon #nature #Buckinghamshire
Updated an alcohol shop
I walked 9.4km in 1h58m25s
Updated 2 benches
Created a bench; Updated a bench
I hiked 19.0km in 4h35m50s
I hiked 19.0km in 4h35m50s
I walked 6.8km in 1h15m36s
Updated an estate_agent office
I walked 4.1km in 55m33s
I walked 1.1km in 10m05s
My First Lapwing!
I went to the London Wetland Centre yesterday, for a day out in nature.
While hiding in a hide, this chap and a friend showed up starting to forage for grubs.
#BirdPhotography #BirdsOfMastodon #Photography #Birds #London #Nature
Created a waste_basket; Updated a cafe and a restaurant; Confirmed an estate_agent office
I walked 6.6km in 1h8m53s



Shortlink
This article has a short URL available: https://drck.me/php72switch-dgj