views:

77

answers:

3

So I'm working on a project written in old-style (no OOP) PHP with no full rewrite in the near future. One of the problems with it currently is that its slow—much of the time is spent requireing over 100 files based on where it is in the boot process.

I was wondering if we could condense this (on deployment, not development of course) into a single file or two with all the require'd text just built in. However, since there are so many lines of code that aren't used for each page, I'm wondering if doing this would backfire.

At its core, I think, it's a question of whether:

<?php
   echo 'hello world!';
?>

is any faster than

<?php
   if(FALSE) {
       // thousands of lines of code here
   }
   echo 'hello world!';
?>

And if so, how much slower?

(Also, if what I've outlined above is a bad idea for some other reasons, please let me know.)

A: 

Keep in mind that PHP will parse all the code it sees, even if it's not run.

It will still take relatively long to process the a file too, and from experience, lots of code will eat up considerable amounts of memory even though they're not executed.

Opcode caching as suggested by @Tim should be your first port of call.

If that is out of the question (e.g. due to server limitations): If the functions are somehow separable into categories, one possibility to make things a bit faster and lighter could be (ab)using PHP's Autoloading by putting the functions into separate files as methods of static classes.

function xyz() {  ... }

would become

class generic_tools
 {
  public static function xyz() {  ... }
 } 

and any call to xyz() is replaced by generic_tools::xyz();

The call would then trigger the inclusion of (e.g.) generic_tools.class.php on demand, instead of including everything at once.

This would require rewriting the function calls to static method calls, which may be dead easy or a bit more difficult (if function calls are cooked up dynamically or something). But beyond that, no refactoring would be needed, because you're not really using any OOP mechanisms.

How much this will actually help strongly depends on the app's architecture and how intertwined the functions are with each other.

Pekka
he's not using any OO.
tandu
@tandu yes, I know. Your point being? The idea is to import all functions into static classes so they can be loaded separately
Pekka
+4  A: 

The difference between the two will be negligible. If most of the execution time is currently spent requiring files you're likely to see a significant boost by using an optcode cache like APC, if you are not already.

Other than that - benchmark, find out exactly where the bottlenecks are. In my experience requires are often the slowest part of an old-style procedural PHP app, but even with many included files I'd be surprised if these all added up to a 'slow' app.

Edit: ok, a quick 'n dirty benchmark. I created three 'hello world' PHP scripts like the example. The first (basic.php) was just echoing the string. The second (complex.php) included an if false statement that contained ~5000 lines of PHP code pasted in from another app. The third (require.php) included the same if statement but required in the ~5000 lines of code from another file.

Page generation time (as measured by microtime()) between basic.php and complex.php was around ~0.000004 seconds, so really not significant. Some more comprehensive results from apache bench:

                     without APC         with APC
                req/sec   avg (ms)  req/sec   avg (ms)
basic.php:     7819.87     1.277    6960.49    1.437
complex.php:    346.82     2.883     352.12    2.840
require.php:   6819.24     1.446    5995.49    1.668

APC's not doing a lot here but using up memory, but it's likely to be a different picture in a real world app.

Tim Fountain
Using APC is a very good point and should be the OP's first try, hands down. Without caching there will be a notable difference between the two, though, because the code will be parsed in any case
Pekka
Obviously the second will be slower but I doubt it would be by a significant amount. I'll do some benchmarks.
Tim Fountain
Interesting. The reason why `require.php` is so much faster is because the `require` isn't actually happening because it's in the if block, right?
Pekka
Actually that is interesting, I always thought require always executed, and it was include that only ran conditionally. But that must have changed at some point as if I change the if to if true, require.php performs much more in line with complex.php. So in the OP's case, if not all the includes are required all the time, he'll see best results with conditional requires or autoloading as you suggested.
Tim Fountain
A: 

require does have some overhead. 100 requires is probably a lot. Parsing an entire file that has the 100 includes is probably slow too. The overhead from require might cost you more, but it is hard to say. It might not cost you enough.

All benchmarks are evil, but here is what I did:

ran a single include of a file that was about 8000 lines (didn't do anything useful each line, just declares a variable). Compared to the time it takes to run an include of an 80 line file (same declarations) 100 times. Results were inconclusive.

Is the including of the files really causing the problem? Is there not something in the script execution that can be optimized? Caching may be an option..

tandu