I was in the middle of a code review a simple question came up: “What’s the fastest way to output a segmented string in PHP?”

echo '<div>';
echo '<span>';
echo 'This is a random number: ' . mt_rand(1,100);
echo '</span>';
echo '</div>';

– OR –

$html  = '<div>';
$html .= '<span>';
$html .= 'This is a random number: ' . mt_rand(1,100);
$html .= '</span>';
$html .= '</div>';
echo $html;

My initial guess was that calling echo as little as possible during a request would end up performing better as there would be no need to interact with an output buffer or perform other logic tied to STDOUT.

I ended up asking a few friends and colleges what they thought about the question and most responded with “hu?” After telling them that I was in fact serious the majority of their opinions fell on echo being the winner. Still, others thought of ways to get a segmented string out faster, like pushing them onto an array and executing echo implode('', $array);

This difference of opinion got me thinking about what was truly the most efficient way to output a collection of strings? Curiosity got the best of me and I quickly setup some profiling tests using my Bench Class to find out the answer.

Profiling Setup

I used the following code in order to get enough data points for a solid performance comparison.

$samples = 40;
$sets    = array(10,20,50,100,500,1000,1500,2000,2500,3000);
$results = array();
foreach($sets as $iterations) {
  $results[$iterations] = array();
  for($i=0; $i<$samples; $i++) {
    Bench::start();
    for($j=0;$j<$iterations;$j++) {
      // ... Output Test ...
    }
    $results[$iterations][] = Bench::stop();
    Bench::reset();
  }
}

Output Tests

I tested the performance using four different methods of outputting data…

Echo

for($j=0;$j<$iterations;$j++) {
  echo 'abcdefghijklmnopqrstuvwxyz0123456789';
}

Print

for($j=0;$j<$iterations;$j++) {
  print 'abcdefghijklmnopqrstuvwxyz0123456789';
}

Concatenation

$x = '';
for($j=0;$j<$iterations;$j++) {
  $x .= 'abcdefghijklmnopqrstuvwxyz0123456789';
}
echo $x;

Array + Implode

$x = array();
for($j=0;$j<$iterations;$j++) {
  $x[] = 'abcdefghijklmnopqrstuvwxyz0123456789';
}
echo implode('', $x);

Environment

I ended up testing with the php-cli in order to avoid the extra overhead of a browser and web server. When I attempted to test the performance in a browser it yielded vastly different datasets from one test to another.

Results

So this is what I ended up with…

Raw Numbers

  10 20 50 100 500 1000 1500 2000 2500 3000
Concat 3.80E-05 6.04E-05 0.0001506 0.0003327 0.0018855 0.0044077 0.0063608 0.0079579 0.0099115 0.0118193
Implode 4.00E-05 6.05E-05 0.0001454 0.0003285 0.0017583 0.0040021 0.0059396 0.0081685 0.0106799 0.0131378
Echo 2.43E-05 4.36E-05 0.0001046 0.0004600 0.0021742 0.0050115 0.006305 0.0086550 0.0105163 0.0133090
Print 5.76E-05 0.000119 0.0002459 0.0006077 0.0026465 0.0048339 0.0065905 0.0086254 0.0109871 0.0130858

Graphs

10-100 Results

500-3000 Results

Conclusions

As one can see there is very little difference in speed, and performance seems to scale up linearly. After playing around with various tested sizes I felt that going past the 3000 iterations mark would have been futile as it’s already quite a stretch that anyone would call echo that much within a single request.

While this post may be trivial it at least shows that there is no real performance benefits to using any of the four methods over one another. However, that’s not to say that all methods are equal when one is aiming towards maintainability – but that it another topic for a different day.

Summary

If you feel I’ve somehow misrepresented the data then by all means download the testing script, modify it, and educate me.

You can find the testing script and results here: PHP Output Profiling Testing Script.

Tail Multiple Logs with Capistrano

Here’s a quick and easy way to tail log files from multiple hosts using Capistrano and the Foreman gem.Capistrano TaskFirst you’ll need to make sure the fore... Continue reading

Add Eloquent ORM Tab to PHP Debug Bar

Published on August 30, 2015

Doctrine 2 PDO Object

Published on August 17, 2015