Performant PHP work with numbers
PHP is a typeunsafe programming language and when you are looking over the source of beginners you'll see that they work with string functions on numbers and other ugly things. In most cases this will not cause an error but it's really blotted and argue a really bad programming style. I don't say that this way is bad in every case. To calculate the length of a number for example. But there are a few ways to achieve our desired goal and what's the best way? The mathematical way is that we divide the logarithm of the number by the logarithm of 10: log($n) / log(10). Now we can ceil() this result and have the number of digits of $n. Sure, the faster way is adding one and cast to int. But let's have a look on a few implementations and their timings:
$x = ceil(log($num) / log(10)); 0.029807 sec 0.02982 sec 0.029742 sec 0.029871 sec 0.02988 sec
This is a good starting position and we have now a reference point. So let's search for a better solution by using the already mentoined usage of string functions on numbers:
$x = strlen($num); 0.017769 sec 0.017727 sec 0.0177 sec 0.017697 sec 0.017742 sec
Okay, we are better, but let's see, if we can optimize this, by pre casting the number to a string:
$tmp = (string)$num; $x = strlen($tmp); 0.009112 sec 0.009172 sec 0.009155 sec 0.009156 sec 0.009155 sec
...yeah. This looks good for the moment. Now that we know, how we can calculate the length of a number, let's try to split the number digit by digit and save the result in an array. We will look over 4 ways of doing this job here:
1. Division
$arr = array();
for($i = 0; (int)$num > 0; $i++) {
$arr[] = $num % 10;
$num/= 10;
}
2. Access the digits by brackets
$arr = array();
for($i = strlen($num) - 1; $i >= 0 ; $i--) {
$arr[] = $num{$i};
}
3. Access the digits with substr()
$arr = array();
for($i = strlen($num) - 1; $i >= 0 ; $i--) {
$arr[] = substr($num, $i, 1);
}
4. Access the digits with substr(), optimized
$arr = array();
$tmp = (string)$num;
for($i = strlen($tmp) - 1; $i >= 0 ; $i--) {
$arr[] = substr($tmp, $i, 1);
}
So, what do you think is the best? Lets look over the timing table:
div: 0.010299 sec 0.010278 sec 0.010207 sec 0.0102 sec 0.010209 sec brackets: 0.103473 sec 0.103237 sec 0.10262 sec 0.102984 sec 0.102821 sec substr: 0.217405 sec 0.221709 sec 0.217226 sec 0.217958 sec 0.21719 sec substr opt: 0.142615 sec 0.139224 sec 0.143382 sec 0.139244 sec 0.139225 sec
Conclusion: If you want to do such work on numbers, you should cast the number to a string before you access any digits. Thereby you will save the conversation from a number to string for every loop. In general, we can state, that you should work as properly as you work with typesafe languages also under PHP to get the best performance.
Sure, the savings are really slim and all benchmarks were run 1000 times to get a readable output. But I think the most important benefit of this post should be the insight, that a clean code performs even better.
