Practical (and impractical) PHP Optimizations

Devolio

Search

Twitter

    Thursday, February 28. 2008

    Practical (and impractical) PHP Optimizations

    I've been seeing a lot of articles popping up lately about PHP Optimizations, particularly within the code (rather than the configuration, server, caching, etc) that I have some nitpicks with.

    My position remains the same: Unless your code is running incredibly slow, you've found every single bug you can possibly find without having nightmares about unit tests, or an optimization that makes more than a 10% improvement in speed (factoring in your margin of error,) don't bother. That said, let's down to brass tacks.
    Each test is run 1000 times and the execution time is averaged over two different ways of achieving the same results. Execution times are rounded to millionths of a second, and taken using microtime. The server is running Ubuntu 7.10 server with PHP 5.2.3-1 and Apache 2, and will not have anything else open to keep the margin of error as low as possible. To be on the safe side, my margin of error (between doing this for years, and my guesstimate after running countless hours of benchmarks) is about 15% +/-.



    Ordered from most performance impact to least performance impact


    PDO vs. Native PHP MySQL Select (without where condition)


    Native PHP MySQL
    0.003249 - 0.442145 seconds (avg 0.222697 seconds)

    PDO Abstraction
    0.007958 - 0.026665 seconds (avg 0.017311 seconds)


    Without getting into too many of the intricacies, PDO is ~90% faster on average for selects (and averaged with all 3 loop types!).



    Associative Array Quoting vs. None


    No Quotes
    0.006722 - 0.009518 seconds (avg 0.008120 seconds)

    Quotes
    0.003404 - 0.004184 seconds (avg 0.003794 seconds)


    This is a horrible thing to do in the first place. Quoting associative array elements is ~74% faster on average.



    preg_replace() vs. ereg_replace() vs. str_replace()


    str_replace()
    0.001449 - 0.001796 seconds (avg 0.001622 seconds)

    preg_replace()
    0.002752 - 0.003861 seconds (avg 0.003306 seconds)

    ereg_replace()
    0.002558 - 0.002854 seconds (avg 0.002706 seconds)


    str_replace() is ~50% faster on average. Better to replace simpler things not requiring regex with str_replace(), and ereg_replace() will be phased out in php6.



    PDO vs. Native PHP MySQL (with where condition)


    Native PHP MySQL
    0.225475 - 1.021669 seconds (avg 0.623572 seconds)

    PDO Abstraction
    0.175147 - 0.462859 seconds (avg 0.319003 seconds)


    Once again, PDO is noticeably ~48% faster on average, less a few intricacies. Native PHP MySQL seems to lag a little bit as the requests stack up.



    Static vs. Non Static Methods


    Static Method
    0.001223 - 0.001494 seconds (avg 0.001358 seconds)

    Non-Static Method
    0.002424 - 0.002839 seconds (avg 0.002631 seconds)


    Static Methods are without a doubt faster, ~48% on average.



    Error Suppression vs. None


    Error Suppression
    0.008674 - 0.011197 seconds (avg 0.009935 seconds)

    No Error Suppression
    0.004963 - 0.008407 seconds (avg 0.006685 seconds)


    Error suppression ( @function() ) is sssslllloooowwww. ~32% improvement on average.



    Unset vs. None


    No Unset
    0.000993 - 0.001760 seconds (avg 0.001376 seconds)

    Unset
    0.000949 - 0.001011 seconds (avg 0.000980 seconds)


    Freeing up memory with unset as you're done with vars. ~28% improvement on average.



    PDO vs. Native PHP MySQL inserting


    Native PHP MySQL
    0.885488 - 1.675858 seconds (avg 1.280673 seconds)

    PDO Abstraction
    0.567447 - 1.329165 seconds (avg 0.948306 seconds)


    PDO trounces Native PHP MySQL again, about ~25% better on average.



    Split() vs. Explode()


    split()
    0.001813 - 0.002271 seconds (avg 0.002042 seconds)

    explode()
    0.001678 - 0.003626 seconds (avg 0.002652 seconds)


    Split can take regular expressions as delimiters, and runs faster too. ~23% on average.



    echo ''; vs. echo '', '';


    Echo Per Line
    0.009819 - 0.017965 seconds (avg 0.013892 seconds)

    Echo Multiple Args
    0.009607 - 0.012264 seconds (avg 0.010935 seconds)


    The numbers agree; ~21% improvement on average.



    While() vs. For() vs. Foreach()


    while
    0.000306 - 0.000313 seconds (avg 0.000309 seconds)

    for
    0.000321 - 0.000340 seconds (avg 0.000330 seconds)

    foreach
    0.000330 - 0.000344 seconds (avg 0.000337 seconds)


    The difference is negligible (~13% maximum.) As long as the condition doesn't recursively call a function, it's more of a situational choice.



    Extra time taken from recursive function calls


    while
    0.000422 - 0.000441 seconds (avg 0.000431 seconds)

    for
    0.000323 - 0.000352 seconds (avg 0.000337 seconds)


    ~5% and 28% slower on average than without recursive calling.



    is_numeric() vs. ctype_digit()


    ctype_digit()
    0.002009 - 0.002462 seconds (avg 0.002235 seconds)

    is_numeric()
    0.001864 - 0.002074 seconds (avg 0.001969 seconds)


    is_numeric() is faster by ~11%.



    in_array() vs. iteration


    in_array()
    0.000987 - 0.001431 seconds (avg 0.001209 seconds)

    Iteration
    0.001245 - 0.001414 seconds (avg 0.001329 seconds)


    Negligible, just 9% without doing too much in an iteration.



    Echo vs. Print


    Echo
    0.000929 - 0.001255 seconds (avg 0.001092 seconds)

    Print
    0.000980 - 0.001396 seconds (avg 0.001188 seconds)


    Negligible difference (~8%), but echo comes out to be a little quicker overall.



    Incrementing undefined variable vs. defined


    Undefined
    0.000191 - 0.000197 seconds (avg 0.000194 seconds)

    Defined
    0.000179 - 0.000185 seconds (avg 0.000182 seconds)


    Negligible. ~6%



    Numeric vs. Associative Foreach


    Numeric foreach
    0.001542 - 0.001718 seconds (avg 0.001630 seconds)

    Associative foreach
    0.001599 - 0.001727 seconds (avg 0.001663 seconds)


    Completely negligible. ~1%



    " vs. '


    '
    0.000813 - 0.000974 seconds (avg 0.000893 seconds)

    "
    0.000856 - 0.000939 seconds (avg 0.000897 seconds)


    Completely negligible. ~1%



    Require_once vs. Include_once()


    include_once()
    0.013582 - 0.015804 seconds (avg 0.014693 seconds)

    require_once()
    0.013545 - 0.015840 seconds (avg 0.014692 seconds)


    Completely negligible. ~1%


    Is there something I completely missed? Disagree with me? Let me know, I encourage you to let me know what you do to optimize.

    Trackbacks

    Practical (and impractical) PHP Optimizations - Devolio
    Practical (and impractical) PHP Optimizations - Devolio
    Weblog: roScripts - Webmaster resources and websites
    Tracked: Feb 29, 00:14

    Comments
    Display comments as (Linear | Threaded)

    #1 - Sterling 2008-02-28 11:17 - (Reply)

    You should include the code samples you used for these tests.

    #1.1 - Joey said:
    2008-02-28 12:04 - (Reply)

    I'll be posting the class to benchmark with and other stuff after the weekend.

    #2 - Tordek said:
    2008-02-28 13:29 - (Reply)

    How about include vs require, and include/require vs include/require_once?

    Also, I didn't get "echo ''; vs echo '','';".

    You can also test echo "a","b"; vs "a"."b";, and echo ''; vs printf('');.

    #2.1 - Joey said:
    2008-02-28 13:38 - (Reply)

    I'll add include/require, _once comparisons and all of the possible combinations of print/printf/echo when I update all of them this weekend. Thanks for all of the suggestions. :-)

    echo ''; vs echo '','';

    is the difference between multiple echoes (as in multiple lines,) multiple parameters (, separated,) and concatenated echoes (another one coming after the update.)

    #3 - EllisGL 2008-02-28 20:51 - (Reply)

    I think one is missed with in_array() vs. iteration.

    say I have an array $a = array('apple', 'orange', 'grape', 'monkey');

    in_array() is slow, iteration can be slow too..

    I do my arrays as:
    $a = array('apple'=>1, 'orange'=>1, 'grape'=>1, 'monkey'=>1)

    I can check it with:
    if($a['apple'])
    {
    }

    I've read and seen some benches that show it to be a lot faster.

    #3.1 - Joey said:
    2008-02-28 21:46 - (Reply)

    I'll add in a few more methods for testing arrays with the next update. This one is more for testing for a specific string inside of an array, rather than if it's set.

    #4 - André Medeiros 2008-02-29 10:55 - (Reply)

    I would disagree against the single and double quote argument.

    Double quotes are really slower because PHP will try to interpret what's inside, like special characters, variables and so on.

    #4.1 - EllisGL 2008-02-29 10:59 - (Reply)

    Actually it's depends how they are used..

    $a = "";
    is faster than
    $a = '';

    But
    $a = 'some string';
    is faster than
    $a = "some string";

    #4.1.1 - André Medeiros 2008-03-03 23:32 - (Reply)

    Heh, I don't think the first case would be of much use in The Real World (TM) ;-)

    Thanks for pointing it out tho.

    #4.1.1.1 - EllisGL 2008-03-04 09:08 - (Reply)

    Some people like to setup the variable before hand, even if they do not have a value assigned to them.

    No problem.

    #5 - David P said:
    2008-04-09 11:47 - (Reply)

    What about array_pop($array) vs $array[]?

    I use the latter 99% of the time.

    #6 - David P said:
    2008-04-09 11:48 - (Reply)

    My last one was a mistake. I meant array_push($array) vs $array[]

    #6.1 - Joey said:
    2008-04-09 11:59 - (Reply)

    David,

    Pretty soon I'll be re-running all of the tests from the first run, and adding in all of the tests that have been suggested (and releasing the test scripts).

    Thanks for suggesting another comparison to make. If you have any others to add, let me know. I've been racking my brain trying to find some others to test.

    #7 - David P said:
    2008-04-09 13:16 - (Reply)

    Syntax (bracket versus colon/semi-colon):

    if ($a): ... endif;
    if ($a) { ... }
    if ($a) ...

    Inline if:

    $var = ($a) ? 1 : 0;
    if ($a)
    $var = 1;
    else
    $var = 0;

    Boolean if:

    if ($a) {
    $var = 1;
    }

    if ($a > 0) {
    $var = 1;
    }

    #7.1 - Joey said:
    2008-04-09 13:22 - (Reply)

    Thanks for the quick feedback, David.

    I appreciate the ideas for more comparisons.

    #8 - David P said:
    2008-04-10 13:53 - (Reply)

    SQL Injection prevention:

    $sql = "SELECT FROM table WHERE id = " . mysql_real_escape_string($var);

    $sql = sprintf("SELECT
    FROM table WHERE id = %u", $var);

    #9 - James said:
    2008-05-01 12:38 - (Reply)

    Great set of comparisons.


    Add Comment

    Enclosing asterisks marks text as bold (*word*), underscore are made via _word_.
    Standard emoticons like :-) and ;-) are converted to images.
    E-Mail addresses will not be displayed and will only be used for E-Mail notifications