performance difference between strrev() and array_reverse() - php

is there any kind of performance difference between these two?
$bin = 1000 //8 in decimal
$bin_a = strrev($bin);
$bin_a = str_split($bin_a);
or
$bin_b = str_split($bin);
$bin_b = array_reverse($bin_b);
or are there any function to convert string to array and reverse at the same time?
I want to manually convert binary to decimal without native php function,
or any simpler way to do this?

Not a meaningful difference.
And not diffifcult to test out. You should be able to write a test like this without any trouble whatsoever.
<?php
$start_a = microtime(true);
$bin = "1000"; //8 in decimal
for ($n = 0; $n < 1000000; $n++) {
$bin_a = strrev($bin);
$bin_a = str_split($bin_a);
}
$end_a = microtime(true);
echo "Took ", $end_a - $start_a, " seconds \n";
$start_b = microtime(true);
for ($n = 0; $n < 1000000; $n++) {
$bin_b = str_split($bin);
$bin_b = array_reverse($bin_b);
}
$end_b = microtime(true);
echo "Took ", $end_b - $start_b, " seconds \n";
Output, for a million repetitions:
Took 0.26819205284119 seconds
Took 0.39758610725403 seconds
If you are optimizing for this, you are most likely doing it wrong. :)

Related

Cannot detect any meaningful timing difference in PHP (constant timing attack)

There's quite a few articles around PHP stating that constant timing attacks are possible when doing direct string comparisons. I've written some sample code to try and determine the order of magnitude difference but it's showing that it's not always the case that one is quicker than the other, even when doing millions of tests.
You would expect the first iteration active time to be quicker, as the first character is wrong in the string and thus the comparison can bail out, but it's not always the case.
$target = 'hello-world';
$comparison = ['Xello-world', 'hello-worlX'];
foreach($comparison as $x){
$time = 0;
$total = 500000;
for($i = 0; $i < $total; $i++){
$start = microtime(true);
/** Actually perform the comparison */
$result = ($target === $comparison);
$end = microtime(true);
/** Add up so we can compute the average **/
$time += $end - $start;
}
echo "Duration for $x: " . ($time / $total) . PHP_EOL;
}

most efficient means of parsing a simple clearly defined string?

I'm only asking because this is looping millions of times.
string is simply like this:
01-20
Its always like that... 2 digits (leading zero) followed by hyphen and another 2 digits (leading zero). I simply need to assign the first (as integer) to one variable and the second (as integer) to another variable.
str_split? substr? explode? regex?
Given a variable $txt, this has the best performance:
$a = (int)$txt;
$b = (int)substr($txt, -2);
You could measure the performance of different alternatives with a script like this:
<?php
$txt = "01-02";
$test_count = 4000000;
// SUBSTR -2
$time_start = microtime(true);
for ($x = 0; $x <= $test_count; $x++) {
$a = (int)$txt; // numeric conversion ignores second part of string.
$b = (int)substr($txt, -2);
}
$duration = round((microtime(true) - $time_start) * 1000);
echo "substr(s,-2): {$a} {$b}, process time: {$duration}ms <br />";
// SUBSTR 3, 2
$time_start = microtime(true);
for ($x = 0; $x <= $test_count; $x++) {
$a = (int)$txt; // numeric conversion ignores second part of string.
$b = (int)substr($txt, 3, 2);
}
$duration = round((microtime(true) - $time_start) * 1000);
echo "substr(s,3,2): {$a} {$b}, process time: {$duration}ms <br />";
// STR_SPLIT
$time_start = microtime(true);
for ($x = 0; $x <= $test_count; $x++) {
$arr = str_split($txt, 3);
$a = (int)$arr[0]; // the ending hyphen does not break the numeric conversion
$b = (int)$arr[1];
}
$duration = round((microtime(true) - $time_start) * 1000);
echo "str_split(s,3): {$a} {$b}, process time: {$duration}ms <br />";
// EXPLODE
$time_start = microtime(true);
for ($x = 0; $x <= $test_count; $x++) {
$arr = explode('-', $txt);
$a = (int)$arr[0];
$b = (int)$arr[1];
}
$duration = round((microtime(true) - $time_start) * 1000);
echo "explode('-',s): {$a} {$b}, process time: {$duration}ms <br />";
// PREG_MATCH
$time_start = microtime(true);
for ($x = 0; $x <= $test_count; $x++) {
preg_match('/(..).(..)/', $txt, $arr);
$a = (int)$arr[1];
$b = (int)$arr[2];
}
$duration = round((microtime(true) - $time_start) * 1000);
echo "preg_match('/(..).(..)/',s): {$a} {$b}, process time: {$duration}ms <br />";
?>
When I ran this on PhpFiddle Lite I got results like this:
substr(s,-2): 1 2, process time: 851ms
substr(s,3,2): 1 2, process time: 971ms
str_split(s,3): 1 2, process time: 1568ms
explode('-',s): 1 2, process time: 1670ms
preg_match('/(..).(..)/',s): 1 2, process time: 3328ms
The performance of substr with either (s, -2) or (s, 3, 2) as arguments perform almost equally well, provided you use only one call. Sometimes the second version came out as the winner. str_split and explode perform rather close, but not as well, and preg_match is the clear looser. The results depend on the server load, so you should try this on your own set-up. But it is certain that regular expressions have a heavy payload. Avoid them when you can do the job with the other string functions.
I edited my answer when I realised that you can cast the original string immediately to int, which will ignore the part it cannot parse. This practically means you can get the first part as a number without calling any of the string functions. This was decisive to make substr the absolute winner!
Try to convert the string to an array then use each array index to different variable your want
<?php
$str = '01-20'
$number = explode('-',$str);
$variable_1 = (int)$number[0];
$variable_2 = (int)$number[1];
?>

PHP array_combine & range VS foreach loop to get array of numbers

I have been thinking about this, for code readability I tend to use php built in functions like range & array_combine to generate an array of numbers like this:
array(
5 => 5,
10 => 10,
15 => 15,
20 => 20,
25 => 25,
...
60 => 60
);
So currently I use this to generate above:
$nums = range(5, 60, 5);
$nums = array_combine($nums, $nums);
I was wondering if there is a speed or memory difference between above approach and simply using loop like this:
for ($i = 5; $i <= 60; $i++) {
$nums[$i] = $i;
$i += 5;
}
I just want to know if my approach is good practice or if someone who would look at my code would try to find out where I live?
The following method seems to be fast for small numbers:
$tmp = range(5,$limit,5);
$tmp = array_combine($tmp, $tmp);
However, the for loop is much faster for bigger numbers:
for($i =5; $i<=$limit; $i += 5)
$tmp[$i] = $i;
Try the following code here:
<?php
$limit = 200;
$time_start = microtime(true);
$tmp = range(5,$limit,5);
$tmp = array_combine($tmp, $tmp);
$time_end = microtime(true);
echo $time_end - $time_start;
echo "<br/>";
//print_r($tmp);
echo "<br/>";
$time_start = microtime(true);
$tmp = array();
for($i =5; $i<=$limit; $i += 5)
$tmp[$i] = $i;
$time_end = microtime(true);
echo $time_end - $time_start;
echo "<br/>";
//print_r($tmp);
for $limit = 200 the first method is faster:
1=> 2.0980834960938E-5
2=> 2.1934509277344E-5
range & combination wins!
for $limit = 500 the second method is faster:
1=> 3.7908554077148E-5
2=> 2.9087066650391E-5
for loop wins!
So in my opinion, I would pick the second method (for loop) since for small number, even if the first method is faster, the time difference is negligible. However, for large numbers, the second method is always faster, and that what we care about in computer science, the worst time
Conclusion:
For loop is the winner!

Fastest way of getting a character inside a string given the index (PHP)

I know of several ways to get a character off a string given the index.
<?php
$string = 'abcd';
echo $string[2];
echo $string{2};
echo substr($string, 2, 1);
?>
I don't know if there are any more ways, if you know of any please don't hesitate to add it. The question is, if I were to choose and repeat a method above a couple of million times, possibly using mt_rand to get the index value, which method would be the most efficient in terms of least memory consumption and fastest speed?
To arrive at an answer, you'll need to setup a benchmark test rig. Compare all methods over several (hundreds of thousands or millions) iterations on an idle box. Try the built-in microtime function to measure the difference between start and finish. That's your elapsed time.
The test should take you all of 2 minutes to write.
To save you some effort, I wrote a test. My own test shows that the functional solution (substr) is MUCH slower (expected). The idiomatic PHP ({}) solution is as fast as the index method. They are interchangeable. The ([]) is preferred, as this is the direction where PHP is going regarding string offsets.
<?php
$string = 'abcd';
$limit = 1000000;
$r = array(); // results
// PHP idiomatic string index method
$s = microtime(true);
for ($i = 0; $i < $limit; ++$i) {
$c = $string{2};
}
$r[] = microtime(true) - $s;
echo "\n";
// PHP functional solution
$s = microtime(true);
for ($i = 0; $i < $limit; ++$i) {
$c = substr($string, 2, 1);
}
$r[] = microtime(true) - $s;
echo "\n";
// index method
$s = microtime(true);
for ($i = 0; $i < $limit; ++$i) {
$c = $string[2];
}
$r[] = microtime(true) - $s;
echo "\n";
// RESULTS
foreach ($r as $i => $v) {
echo "RESULT ($i): $v \n";
}
?>
Results:
RESULT (PHP4 & 5 idiomatic braces syntax): 0.19106006622314
RESULT (string slice function): 0.50699090957642
RESULT (*index syntax, the future as the braces are being deprecated *): 0.19102001190186

Speed difference in using inline strings vs concatenation in php5?

(assume php5) consider
<?php
$foo = 'some words';
//case 1
print "these are $foo";
//case 2
print "these are {$foo}";
//case 3
print 'these are ' . $foo;
?>
Is there much of a difference between 1 and 2?
If not, what about between 1/2 and 3?
The performance difference has been irrelevant since at least January 2012, and likely earlier:
Single quotes: 0.061846971511841 seconds
Double quotes: 0.061599016189575 seconds
Earlier versions of PHP may have had a difference - I personally prefer single quotes to double quotes, so it was a convenient difference. The conclusion of the article makes an excellent point:
Never trust a statistic you didn’t forge yourself.
(Although the article quotes the phrase, the original quip was likely falsely attributed to Winston Churchill, invented by Joseph Goebbels' propaganda ministry to portray Churchill as a liar:
Ich traue keiner Statistik, die ich nicht selbst gefälscht habe.
This loosely translates to, "I do not trust a statistic that I did not fake myself.")
Well, as with all "What might be faster in real life" questions, you can't beat a real life test.
function timeFunc($function, $runs)
{
$times = array();
for ($i = 0; $i < $runs; $i++)
{
$time = microtime();
call_user_func($function);
$times[$i] = microtime() - $time;
}
return array_sum($times) / $runs;
}
function Method1()
{
$foo = 'some words';
for ($i = 0; $i < 10000; $i++)
$t = "these are $foo";
}
function Method2()
{
$foo = 'some words';
for ($i = 0; $i < 10000; $i++)
$t = "these are {$foo}";
}
function Method3()
{
$foo = 'some words';
for ($i = 0; $i < 10000; $i++)
$t = "these are " . $foo;
}
print timeFunc('Method1', 10) . "\n";
print timeFunc('Method2', 10) . "\n";
print timeFunc('Method3', 10) . "\n";
Give it a few runs to page everything in, then...
0.0035568
0.0035388
0.0025394
So, as expected, the interpolation are virtually identical (noise level differences, probably due to the extra characters the interpolation engine needs to handle). Straight up concatenation is about 66% of the speed, which is no great shock. The interpolation parser will look, find nothing to do, then finish with a simple internal string concat. Even if the concat were expensive, the interpolator will still have to do it, after all the work to parse out the variable and trim/copy up the original string.
Updates By Somnath:
I added Method4() to above real time logic.
function Method4()
{
$foo = 'some words';
for ($i = 0; $i < 10000; $i++)
$t = 'these are ' . $foo;
}
print timeFunc('Method4', 10) . "\n";
Results were:
0.0014739
0.0015574
0.0011955
0.001169
When you are just declaring a string only and no need to parse that string too, then why to confuse PHP debugger to parse. I hope you got my point.
Live benchmarks:
http://phpbench.com/
There is actually a subtle difference when concatenating variables with single vs double quotes.
#Adam's test used
"these are " . $foo
note that the following is even faster:
'these are ' . $foo;
this is due to the fact, that a double quoted "string" gets evaluated, where a single quoted 'string' is just taken as is...
Don't get too caught up on trying to optimize string operations in PHP. Concatenation vs. interpolation is meaningless (in real world performance) if your database queries are poorly written or you aren't using any kind of caching scheme. Write your string operations in such a way that debugging your code later will be easy, the performance differences are negligible.
#uberfuzzy Assuming this is just a question about language minutia, I suppose it's fine. I'm just trying to add to the conversation that comparing performance between single-quote, double-quote and heredoc in real world applications in meaningless when compared to the real performance sinks, such as poor database queries.
Any differences in execution time are completely negligible.
Please see
NikiC's Blog: Disproving the Single Quotes Performance Myth for a technical explanation how interpolation and concatenation works in PHP and why it is absolutely pointless to care about their speed.
Don't waste time on micro-optimizations like this. Use a profiler to measure the performance of your application in a real world scenario and then optimize where it is really needed. Optimising a single sloppy DB query is likely to make a bigger performance improvement than applying micro-optimisations all over your code.
there is a difference when concatenating variables... and what you are doing with the result... and if what you are doing is dumping it to output, is or isn't output buffering on.
also, what is the memory situation of the server? typically memory management on a higher level platform is worse than that at lower platforms...
$a = 'parse' . $this;
is managing memory at the user code platform level...
$a = "parse $this";
is managing memory at the php system code platform level...
so these benchmarks as related to CPU don't tell the full story.
running the benchmark 1000 times vs running the benchmark 1000 times on a server that is attempting to run that same simulation 1000 times concurrently... you might get drastically different results depending on the scope of the application.
I seem to remember that the developer of the forum software, Vanilla replaced all the double quotes in his code with single quotes and noticed a reasonable amount of performance increase.
I can't seem to track down a link to the discussion at the moment though.
Just to add something else to the mix, if you are using a variable inside a double quoted string syntax:
$foo = "hello {$bar}";
is faster than
$foo = "hello $bar";
and both of these are faster than
$foo = 'hello' . $bar;
Double quotes can be much slower. I read from several places that that it is better to do this
'parse me '.$i.' times'
than
"parse me $i times"
Although I'd say the second one gave you more readable code.
Practically there is no difference at all! See the timings: http://micro-optimization.com/single-vs-double-quotes
It should be noted that, when using a modified version of the example by Adam Wright with 3 variables, the results are reversed and the first two functions are actually faster, consistently. This is with PHP 7.1 on CLI:
function timeFunc($function, $runs)
{
$times = array();
for ($i = 0; $i < $runs; $i++)
{
$time = microtime();
call_user_func($function);
#$times[$i] = microtime() - $time;
}
return array_sum($times) / $runs;
}
function Method1()
{
$foo = 'some words';
$bar = 'other words';
$bas = 3;
for ($i = 0; $i < 10000; $i++)
$t = "these are $foo, $bar and $bas";
}
function Method2()
{
$foo = 'some words';
$bar = 'other words';
$bas = 3;
for ($i = 0; $i < 10000; $i++)
$t = "these are {$foo}, {$bar} and {$bas}";
}
function Method3()
{
$foo = 'some words';
$bar = 'other words';
$bas = 3;
for ($i = 0; $i < 10000; $i++)
$t = "these are " . $foo . ", " . $bar . " and " .$bas;
}
print timeFunc('Method1', 10) . "\n";
print timeFunc('Method2', 10) . "\n";
print timeFunc('Method3', 10) . "\n";
I've also tried with '3' instead of just the integer 3, but I get the same kind of results.
With $bas = 3:
0.0016254
0.0015719
0.0019806
With $bas = '3':
0.0016495
0.0015608
0.0022755
It should be noted that these results vary highly (I get variations of about 300%), but the averages seem relatively steady and almost (9 out of 10 cases) always show a faster execution for the 2 first methods, with Method 2 always being slightly faster than method 1.
In conclusion: what is true for 1 single operation (be it interpolation or concatenation) is not always true for combined operations.
Yes, originally this is about PHP5, however in few months arrive PHP8 and today the best option tested over my PHP 7.4.5 is use PHP - Nowdoc (tested over WIN 10 + Apache and CentOs 7 + Apache):
function Method6(){
$k1 = 'AAA';
for($i = 0; $i < 10000; $i ++)$t = <<<'EOF'
K1=
EOF
.$k1.
<<<'EOF'
K2=
EOF
.$k1;
}
here the method #5 (using Heredoc to concatenat):
function Method5(){
$k1 = 'AAA';
for($i = 0; $i < 10000; $i ++)$t = <<<EOF
K1= $k1
EOF
.<<<EOF
K2=$k1
EOF;
}
the methods 1 to 4 is in beginning of this post
In all my tests the "winner" is method #6 (Newdoc), no't very easy to read, but very fast in CPU and ever using the function function timeFunc($function) by #Adam Wright.
I have tested php 7.4 and php 5.4 with following test cases, It was little still confusing to me.
<?php
$start_time = microtime(true);
$result = "";
for ($i = 0; $i < 700000; $i++) {
$result .= "THE STRING APPENDED IS " . $i;
// AND $result .= 'THE STRING APPENDED IS ' . $i;
// AND $result .= "THE STRING APPENDED IS $i";
}
echo $result;
$end_time = microtime(true);
echo "<br><br>";
echo ($end_time - $start_time) . " Seconds";
PHP 7.4 Outputs
1. "THE STRING APPENDED IS " . $i = 0.16744208335876
2. 'THE STRING APPENDED IS ' . $i = 0.16724419593811
3. "THE STRING APPENDED IS $i" = 0.16815495491028
PHP 5.3 Outputs
1. "THE STRING APPENDED IS " . $i = 0.27664494514465
2. 'THE STRING APPENDED IS ' . $i = 0.27818703651428
3. "THE STRING APPENDED IS $i" = 0.28839707374573
I have tested so many times, In php 7.4 it seems to be all 3 test cases got same result many times but still concatenation have little bittle advantage in performance.
Based on #adam-wright answer, I wanted to know if speed difference happens without no concataining / no vars in a string.
== My questions...
is $array['key'] call or set faster than $array["key"] !?
is $var = "some text"; slower than $var = 'some text'; ?
== My tests with new vars every time to avoid use same memory address :
function getArrDblQuote() {
$start1 = microtime(true);
$array1 = array("key" => "value");
for ($i = 0; $i < 10000000; $i++)
$t1 = $array1["key"];
echo microtime(true) - $start1;
}
function getArrSplQuote() {
$start2 = microtime(true);
$array2 = array('key' => 'value');
for ($j = 0; $j < 10000000; $j++)
$t2 = $array2['key'];
echo microtime(true) - $start2;
}
function setArrDblQuote() {
$start3 = microtime(true);
for ($k = 0; $k < 10000000; $k++)
$array3 = array("key" => "value");
echo microtime(true) - $start3;
}
function setArrSplQuote() {
$start4 = microtime(true);
for ($l = 0; $l < 10000000; $l++)
$array4 = array('key' => 'value');
echo microtime(true) - $start4;
}
function setStrDblQuote() {
$start5 = microtime(true);
for ($m = 0; $m < 10000000; $m++)
$var1 = "value";
echo microtime(true) - $start5;
}
function setStrSplQuote() {
$start6 = microtime(true);
for ($n = 0; $n < 10000000; $n++)
$var2 = 'value';
echo microtime(true) - $start6;
}
print getArrDblQuote() . "\n<br>";
print getArrSplQuote() . "\n<br>";
print setArrDblQuote() . "\n<br>";
print setArrSplQuote() . "\n<br>";
print setStrDblQuote() . "\n<br>";
print setStrSplQuote() . "\n<br>";
== My Results :
array get double quote 2.1978828907013
array get single quote 2.0163490772247
array set double quote 1.9173440933228
array get single quote 1.4982950687408
var set double quote 1.485809803009
var set single quote 1.3026781082153
== My conclusion !
So, result is that difference is not very significant. However, on a big project, I think it can make the difference !

Categories