Jaslabs: High performance Software

High Performance Software

Optimizing PHP objects

By Justin Silverton 

The following tips can help in optimizing object-orientated PHP.

1. Initialise all variables before use.

2. Dereference all global/property variables that are frequently used in a method and put the values in local variables if you plan to access the value more than twice.

3. Try placing frequently used methods in the derived classes.

Warning: as PHP is going through a continuous improvement process, things might change in the future.

More Details

I have found that calling object methods (functions defined in a class) are about twice as slow as a normal function calls. To me that’s quite acceptable and comparable to other OOP languages.

Inside a method (the following ratios are approximate only):

1. Incrementing a local variable in a method is the fastest. Nearly the same as calling a local variable in a function.
2. Incrementing a global variable is 2 times slow than a local var.
3. Incrementing a object property (eg. $this->prop++) is 3 times slower than a local variable.
4. Incrementing an undefined local variable is 9-10 times slower than a pre-initialized one.
5. Just declaring a global variable without using it in a function also slows things down (by about the same amount as incrementing a local var). PHP probably does a check to see if the global exists.
6. Method invocation appears to be independent of the number of methods defined in the class because I added 10 more methods to the test class (before and after the test method) with no change in performance.
7. Methods in derived classes run faster than ones defined in the base class.
8. A function call with one parameter and an empty function body takes about the same time as doing 7-8 $localvar++ operations. A similar method call is of course about 15 $localvar++ operations.

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • DZone
  • Slashdot
  • StumbleUpon
  • Technorati

20 Comments so far

  1. Sascha Goebel July 22nd, 2006 2:28 am

    Interresting stuff. How did you measure these?

  2. Enalung July 23rd, 2006 3:16 pm

    I’ve done similar tests myself. In order to time them, I would usualy place the code to test within a loop and execute it at least 1000 time to get a good test. Before and after the loop, simply call the php function microtime and store the result in a variable. The difference between the two is the time it took to execute all 1000 times. Divide by 1000 and you get the average time.

  3. Eugene Panin July 24th, 2006 2:08 am

    I think the better way to optimize is to use design patterns.
    http://en.wikipedia.org/wiki/Design_pattern_%28computer_science%29

  4. justin July 24th, 2006 12:51 pm

    I used the pear framework package for benchmarking

    http://pear.php.net/package/benchmark/redirected

  5. Jeff Moore July 24th, 2006 11:25 pm

    I’m afraid I don’t agree with this advise.

    I was not able to find any significant difference between calling a method in a base class or a subclass.

    In my tests in PHP 5.1.2, a method call is only 30% slower than a function call.

    Interestingly, the speed of a method call with no parameters was almost exactly the speed of a function call with one parameter. This is to be expected because the object is a hidden parameter to the method, which becomes the $this variable. Favoring functions over methods is a false optimization if your function would require one more parameter than the method.

    The speed of incrementing is largely irrelevant to the overall speed of a PHP program. Generally, your performance problems lie elsewhere (database, IO, and includes).

    I don’t know what to make of the variable initialization claim, except to say that this is irrelevant as a contributer to performance problems in PHP programs. I did not investigate this one.

    The statement global $test actually creates a reference to the global variable. If you var_dump($GLOBALS), you will see the variable created if it does not already exist, even if you don’t assign it a value.

    Don’t perturb your program design in the name of tiny or misleading performance gain. You will only gain a fraction of a percentage of execution time, if you don’t actually end up making the program slower. However, you loose many more units of maintainability. First, write the program to be correct and maintainable. Then, if the program is slow, profile it and look for opportunities to improve it.

    See also Flawed Microbenchmarks.

  6. justin July 25th, 2006 12:10 am

    The link you mentioned offers almost no information.

    (http://www.procata.com/blog/archives/2005/02/24/flawed-microbenchmarks/)

    If you want to plug your own blog…just tell us.

    I agree with your statement about designing your applications with maintainability in mind.

  7. Ian July 25th, 2006 9:50 am

    Unless you are creating a massive application that is loading an insane ammount of objects and files, this does seem like it will cause more problems in the long run.

    Like Jeff said, look at your IO to speed stuff up. Are your queries optimized? Are you including one large file, or smaller one’s as needed?

    I’ve sped up pages 100% by optimizing queries and breaking out a massive include file. I think the most usefull part is declaring variables.

  8. Marcus Bointon July 25th, 2006 10:34 am

    I agree with Jeff. think that while this advice may be true, it is not very helpful. Tuning the kind of variable initialisation and other minor tweaks might possibly speed up your app by 2% overall if you applied them everywhere (possibly thousands of code changes which could introduce errors). Using a PHP optimiser/accelerator will often get you 500% without having to touch your code, and in more complex systems, a shared object cache like memcached can give even more. You also failed to mention MySQL’s excellent query cache which can make a huge difference to query times.
    Microbenchmarking with tools like pear’s benchmarker is all very well, but it doesn’t identify bottlenecks in your application, which are usually at the design pattern level. You’d be much better off using xdebug’s profiler before taking any of the advice here - in my own profiling I’ve often found that object initialisation is slower than database queries!

  9. Matt Todd July 25th, 2006 10:48 am

    @Eugene Panin: I’d not think design patterns to be a great way to boost performance: it seems to me to be more of a design or architectural optimization, not performance.

    M.T.

  10. Greg Donald July 25th, 2006 1:04 pm

    PHP OO is a dog. Don’t use it.

    Here are some actual benchmarks:

    http://destiney.com/benchmarks

  11. justin July 25th, 2006 1:17 pm

    everyone who posted comments here are under the impression that I am saying these are the end-all and be-all of optimizations.

    Yes, I realize that there are many other things you can do, I was merely pointing some things out that can help you squeeze out that last bit of performance from your code.

    Here are a couple of responses to comments: “You also failed to mention MySQL’s excellent query cache which can make a huge difference to query times”.

    I do recommend (and use) using opcode optimizers such as zend or ion cube because they can help speed up execution time. If we’re going to go that route, glib compression is a good way to go as well.

    as for mysql query caching, it will work well for one server but does not scale over mass amounts of servers. For multiple servers,

    I would use memcached: http://www.danga.com/memcached/

    “Microbenchmarking with tools like pear’s benchmarker is all very well, but it doesn’t identify bottlenecks in your application, which are usually at the design pattern level. You’d be much better off using xdebug’s profiler before taking any of the advice here - in my own profiling I’ve often found that object initialisation is slower than database queries!”

    These fixed aren’t going to help with complete design flaws or database queries. I thought by not mentioning those, I made it pretty clear.

  12. justin July 25th, 2006 1:20 pm

    Thanks for the site Greg.

  13. justin July 25th, 2006 1:47 pm

    A rule about comments and moderation: I will not tolerate insults or other comments of this sort on the jaslabs site. I do understand people might have opinions about my articles, but when you insult me, my profession, this site, or the way I do things, you are just asking to get your comments removed.

    I welcome other people’s viewpoints. But please keep them constructive.

  14. Never optimize (link) July 25th, 2006 3:36 pm

    Greg/others: So OO shouldn’t be used because it’s slower than functional programming? Have you ever created a larger system? ;-)

    Never optimize anything - *unless* you have serious bottlenecks, in which case you optimize after you’ve implemented the solution the correct way - becuase then you know what tradeoffs you’ll have to make to optimize it.

    - Bjorn

  15. Jeff Moore July 25th, 2006 4:56 pm

    Please feel free to go directly to the article I linked to on Flawed Benchmarks. The point being that many times micro-benchmarks don’t measure what we think they are measuring and that time spent concentrating on the micro performance issues would be better spent on real performance issues. Its called prioritization and opportunity cost.

    Sorry Greg, but, the OO benchmarks at http://destiney.com/benchmarks are a good example of bad benchmarks. These benchmarks set up a straw man by picking a nonsense task, and implementing it in a way in OO that no-one would actually do. I can show that anything is faster than anything with this technique.

    OO used properly is not significantly slower than code that avoids objects. That is the point I wanted to get across with my comments here.

    Remember, there is no significant difference in performance between:
    $obj->method();
    and
    func($data);

    Its only when you compare
    $obj->method();
    with
    func();

    that you get a difference, but really that is comparing apples and oranges. Taking micro benchmarks out of context and trying to draw macro conclusions about what is faster is exactly the kind of thing that I’m saying watch out for.

  16. Vinu Thomas July 26th, 2006 11:58 pm

    Any reason why methods in derived classes run faster than ones defined in the base class?

  17. Alfred July 27th, 2006 2:39 am

    Great post, very useful for my own coding.

  18. coiso October 6th, 2006 11:05 pm

    class a
    {
    var $somevar;
    }
    class b extends a
    {

    }

    $object= new a;
    $object->somevar=”I’m a var”;

    $newobject = new b;

    echo $object->somevar; // Works
    echo $newobject>somevar; // Doesn’t work. Why? How to make it work?

  19. justin October 7th, 2006 11:11 pm

    This won’t work because your objects instances are not connected in any way, but their definitions are.

    So,

    for this to work: echo $newobject->somevar;

    you first need to initialize it with a variable such as $newobject->somvar = 5;

  20. […] Jaslabs » Optimizing PHP objects […]

Leave a reply