views:

548

answers:

10

I'm modifying some code in which the original author built a web page by using an array thusly:

 $output[]=$stuff_from_database;
 $output[]='more stuff';
 // etc
 echo join('',$output);

Can anyone think of a reason why this would be preferable (or vice versa) to:

 $output =$stuff_from_database;
 $output .='more stuff';
 // etc
 echo $output;
A: 

The bottom will reallocate the $output string repeatedly, whereas I believe the top will just store each piece in an array, and then join them all at the end. The original example may end up being faster as a result. If this isn't performance sensitive, then I would probably append, not join.

dvorak
+13  A: 

It was probably written by someone who comes from a language where strings are immutable and thus concatenation is expensive. PHP is not one of them as the following tests show. So the second approach is performance wise, better. The only other reason that I can think of to use the first approach is to be able to replace some part of the array with another, but that means to keep track of the indexes, which is not specified.

~$ cat join.php
<?php

for ($i=0;$i<50000;$i++) {
$output[] = "HI $i\n";
}

echo join('',$output);
?>


~$ time for i in `seq 100`; do php join.php >> outjoin ; done

real    0m19.145s
user    0m12.045s
sys     0m3.216s

~$ cat dot.php
<?php

for ($i=0;$i<50000;$i++) {
$output.= "HI $i\n";
}

echo $output;
?>


~$ time for i in `seq 100`; do php dot.php >> outdot ; done

real    0m15.530s
user    0m8.985s
sys     0m2.260s
Vinko Vrsalovic
This is a distinct improvement over PHP 4 where it was very much the other way around.
staticsan
A: 

If joined with implode() or join() PHP is able to better optimize that. It goes through all strings in your list, calculates the length and allocates the required space and fills the space. In comparison with the ".=" it has to constantly free() and malloc() the space for the string.

Armin Ronacher
You raise a good point. It will be interesting to measure memory consumption... maybe this can be a bottleneck for a large dataset.
Camilo Díaz
+1  A: 

<!-- Redacted Previous Comment -->

It would appear I had an error in my code so i was doing a no-op and forgot to check.

It would appear Contary to previous testing, and reading previous blogs on the topic, the following conclusions are actually ( tested ) untrue at least for all variants of the above code I can permute.

  1. UNTRUE: String interpolation is slower than string concatenation. (!)
  2. UNTRUE: SprintF is fastest.

In actual tests, Sprintf was the slowest and interpolation was fastest

PHP 5.2.6-pl7-gentoo (cli) (built: Sep 21 2008 13:43:03) 
Copyright (c) 1997-2008 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2008 Zend Technologies
    with Xdebug v2.0.3, Copyright (c) 2002-2007, by Derick Rethans

It may be conditional to my setup, but its still odd. :/

Kent Fredric
+1  A: 

This is a little off topic, but

$output =$stuff_from_database;
$output .='more stuff';
// etc
echo $output;

Is far slower than:

echo = $stuff_from_database;
echo 'more stuff';

In fact, the fastest way to build a string in PHP is:

ob_start();
echo = $stuff_from_database;
echo 'more stuff';
$output = ob_get_contents();
ob_end_clean();

Due to the way that output buffers work and such, it is the fastest way to build a string. Obviously you would only do this if you really need to optimize sting building as it is ugly and doesn't lead to easy reading of the code. And everyone one knows that "Premature optimization is the root of all evil".

Kris Erickson
with minor code corrections around the "echo =" and outputting '$output', this is fastest because the output buffering allocates in 4 or 8KB chunks, rather than just as many as needed (as little as 1 byte).
Alister Bulman
Glad someone remembered
Justin Johnson
+2  A: 

Again, a little bit off topic (not very far), but if you were aiming to put something between the array items being output, then if there was only a few lines to concatenate, join(', ', $output) would do it easily and quickly enough. This would be easier to write, and avoids having to check for the end of the list (where you would not want a trailing ',').

For programmer time, as it is on the order of 1000's of times more expensive than a cpu cycle, I'd usually just throw it into a join if it wasn't going to be run 10,0000+ times per second.

Post-coding micro-optimisation like this is very rarely worth it in terms of time taken vs cpu time saved.

Alister Bulman
+1  A: 

I think the fastest way to do it is with echoes. It's not as pretty and probably not enough faster to be worth the cost in readability.

echo $stuff_from_database
   , 'more stuff'
   , 'yet more'
   // etc
   , 'last stuff';
Kip
A: 

This part of the code is not performance sensitive; it is used to format and display a user's shopping cart info on a low-traffic website. Also, the array (or string) is built from scratch each time and there is no need to address or search for specific elements. It sounds like the array is somewhat more efficient, but I guess it doesn't matter either way for this use. Thanks for all of the info!

A: 

If you're generating a list (e.g. a shopping cart), you should have some code that generates the HTML from each entry fetched from the database.

for ($prod in $cart)
{
  $prod->printHTML();
}

Or something like that. That way, the code becomes a lot cleaner. Of course, this assumes that you've got nice code with objects, rather than a whole moronic mess like my company does (and is replacing).

Dan Udey
A: 

It has already been said, but I think a distinct answer will help.

The original programmer wrote it that way because he thought it was faster. In fact, under PHP 4, it really was faster, especially for large strings.

staticsan