A number of frameworks utilize spl_autoload_register() for dynamically loading classes (i.e. controllers and models). There are a couple of posts on the issue of autoloading and opcode caching. One post in particular has a response by #cletus which references #Rasmus making a number of statements which prove to be unsavoury for those utilizing APC as an opcode cache:
Do PHP opcode cache work with __autoload?
There does not appear to be any discussion as to any possible alternatives to autoloading which do not affect opcode cache performance.
Is there a way to get around the fact autoloaded classes do not get added to the byte code cache?
If not, are there any alternative methods for dynamically loading classes which will get cached?
There seems to still be confusion about this topic, however in most cases it comes down to ease vs performance.
A good mailing list thread to read would be this one on Zend Frameworks mailing list:
http://n4.nabble.com/ZF-and-Autoloading-td640085i20.html
Now, the correlation is here because if you inherit from not-yet-defined
class, you might rely on autoload to define it (though you might also
rely on include), and actually the presence of the autoload facility may
encourage you to use such inheritance. But this is not the autoload
which brings trouble (see after Ramus' "it's not just autoload" in the
blog for some examples of troublesome things).
So the right phrase would be "people which tend to rely on autoload tend
also to use code which defies compile-time binding". Which can't be seen
as autoload fault, of course, and just avoiding autoload won't help a
bit with that - you would also have to rewrite your code so that
compile-time binding could happen. And it has nothing to do with uses of
autoload with "new", for example.
As for the slowdown from the effects described above - i.e., absence of
the compile-time binding - the code indeed becomes a bit slower and such
code can lead in some obscure cases to some trouble to opcode caches
(not in the autoload cases - but in cases where classes are defined
inside conditions, or, God forbid, different definition is created
depending on condition) - but it has next to nothing to do with using
autoload by itself.
The amount of slowdown, however, seem to be greatly exagerrated by
people - it is nothing (and I repeat to be clear - NOTHING) compared
to the performance benefit given by the opcode cache due to the absence
of the disk operations and compilation stage. You could probably
compose an artificial benchmark that would show some significant
slowdown, but I do not believe any real application would even notice.
source: http://n4.nabble.com/ZF-and-Autoloading-td640085i20.html#a640092
Related
I'm looking into methods of reducing maintenance downtime for a certain application.
One thing I could do, is make use of anonymous functions in a way that allows me to re-include a file with a new function definition during runtime. That way the application behaviour can be patched at runtime.
I'm wondering if there are any frameworks out there that would be helpful in implementing this behaviour on a large scale through out an application.
I'm thinking it could help with things like keeping track of which functions are loaded from which files, when/how often to reload them and similar tasks.
I'll leave this open for now, but since I can't find anything at this time, I've started my own project: PHP - Reloaded
PHP's APC extension includes two configuration settings for enabling lazy loading of functions and classes; apc.lazy_functions and apc.lazy_classes.
My websites use APC with noticable performance benefits. They've also had the lazy loading settings enabled and disabled at various times, with no obviously noticable difference.
On the internet there isn't much on the subject other than mere discussion, but no metrics.
Has anybody actually measured the performance impact of using APC lazy loading or are there people who have noticed significant differences using these settings?
When is it advantageous to enable lazy loading? When should it be avoided at all cost?
It depends entirely on the type of application you use APC with.
Most frameworks include autoloading of clases in one way or another. What this basically means is that the apc settings for apc.lazy_functions and apc.lazy_classes is superfluous in the context of dynamically included/required classes on demand.
There's a shift in coding standards with PHP, especially with the acceptance of PSR-1 Coding Standard, frameworks not only implement autoloading, but also ensure that only one class is defined per file.
This in turn means that apc.lazy_classes only copy classes from included files as they are used, but current coding standards ensure that files are included as needed and that included files define only one class, that is immediately used.
Using apc.lazy_functions and apc.lazy_classes with other (older) projects, might give better results.
However, with regard to apc.lazy_functions, that settings only covers global scope functions defined in files. Not individual methods of classes. The nomenclature might be misleading, but class functions are distinctively called methods.
I've read a lot of articles about ZF performance and still can't understand, if I've enabled byte-code caching (APC), does it make sense to use some other tricks? E.g. disabling autoload and using one big php-file with all necessary classes instead.
I was surprised to find that this is the only question on the site tagged performance, autoload, php. What a better place than this to dispel the #1 autoload myth:
Modern, well-designed autoloaders won't break APC (or PHP 5.5's OPcache), and are not any worse for performance than require_once (except for the function call overhead, of course).
Why? Well, now we have spl_autoload_register, which lets you add multiple autoload handlers. This allows each third party library to ship it's own autoloader that knows how to load that library's files, and skip the rest.
For example, Zend Framework 1's Zend_Loader_Autoloader restricts itself to trying to load classes that start with a specific pseudo-namespace -- Zend_ (and anything else the user asks it to load). If it doesn't start with the desired pseudo-namespace, it simply returns and lets the next loader on the stack run. It also knows that it can find Zend_Foo_Bar_Baz in Zend/Foo/Bar/Baz.php, so it doesn't need to search the include path by hand. Like other modern framework autoloaders, it follows the the PSR-0 autoloading standard.
Any dependencies installed via composer also get automatically built namespaced autoloaders in the same way.
It's that include path scouring that makes poorly-designed autoloaders suck. You generally don't see these in modern PHP code. The intense filesystem stat calls that result from trying to find files are a frequent performance drag. Check out this presentation by PHP creator Rasmus Lerdorf, in which he increases the performance of Wordpress through benchmarking, profiling, and careful removal of slow operations like stat calls.
The require_once-everything-up-front from the olden days is is unnecessary when you're using modern libraries and don't have a sucky autoloader. It's only a major win when you disable apc.stat if you're using APC, or fiddling with OPcache's validate_, revalidate_, and enable_file_override INI options if you're using OPcache.
tl;dr: Unless you know that statting include files is your largest bottleneck, the Zend autoloader is just fine, and you don't need to resort to a require_once fest.
Q1)
I'm designing a CMS (-who isn't!) but priority is being given to caching. Literally everything is cached. DB rows, DB id queries, Configuration data, processed data, compiled templates. Currently it has two layers of caching.
The first is a opcode cache or memory cache such as apc, eaccelerator, xcache or memcached. If an entry is not found in there it is then searched for in the secondary slow cache, ie php includes.
Are the opcode caches actually faster than doing a require_once to a php file with a var_export'd array of data in it? My tests are inconclusive as my development box (5.3 of XAMPP) keeps throwing errors installing any of the aforementioned programs.
Q2)
The CMS has numerous helper classes that are autoloaded on demand instead of loading all files. Mostly each has a require before it so no autoloading needs to take place, however this is not the question. Because a page script can have up to 50/60 helper files included I have a feeling that if the site was under pressure it would buckle because of all the i/o that this incurs. Ignore for the moment that there is output cache in place that would remove the need for what I am about to suggest, and also that opcode caches would render this moot. What I have tried to do is join all the helper files required for the scripts execution in one single file. This is achievable and works well, however it has a side effect of greatly increasing the memory usage dramatically even though technically the same code is being used.
What are your thoughts and opinions on this?
Using a compiler cache like APC should help out as it will take your helper files and cache them after they are converted to opcode. That will mean the files will not only be cached but already in opcode so they do not need to be parsed and compiled each time they are required.
Looks like you just have no idea what you want to cache (and why).
You just cannot compare "opcode cache" and "require_once". Opcode cache will cache required code as well as other code.
First, keep in mind that your operating system will cache files in memory if they are being accessed frequently enough.
Also, don't use require_once. It is significantly slower than require. If you aren't using an autoloader, you should be. There is no reason to be manually including files in a modern php application (very few exceptions).
50-60 helper files is crazy. Isn't there some way to combine these? Can't you put them all in a related helper class, like OutputHelper or CacheHelper? That way you only have to include the class, which, again, should be taken care of your autoloader. It sounds to me you're doing something like putting one function per file.
Opcode caching greatly reduces memory usage and execution speed, but I'm not sure what effect it has on require statements.
I agree with ryeguy. require_once is slower than require or include because it has to log every include and check against it. If your only doing one require/include (which you should be for classes) then you don't need require_once or include_once.
Autoloading is great for optimization. As you only will load in classes when needed. So if your app has 500 classes, but only needs 15 to run a certain page/script. Then only those 15 get loaded. Which is nice.
If you take a peak at any big framework. You will notice that they have migrated to using autoloaders. They use to use require_once at the last moment like this example from the Zend Framework Version 1.
require_once 'Zend/Db/Exception.php';
throw new Zend_Db_Exception('Adapter name must be specified in a string');
Zend Framework Version 2 is going to be using auto loaders instead. I believe this is the fastest and it's also the easiest to code for.
In my index.php file I always load some classes used later. From profiler it states it sometimes can take about 20% of entire code. Is there any improvement that can make this process faster?
I would try to make this list of classes shorter, but app is very big and checking all dependencies will be costly.
Op-code caches such as APC and eAccelerator store a compiled version of your scripts in a cache. This dramatically reduces memory usage and loading time for frequently used static scripts.
While using an opcode cache (such as APC) will reduce the impact of loading/parsing/compiling the class, you'll still be loading them all on every page load & doing whatever initialization accompanies a require_once() call. If you were to set up an autoload function then the classes won't be loaded until your code actually needs to use them. There's a little overhead involved in using a class autoloader but it makes the code easier to maintain.
As always, YMMV, so benchmark your application to see if it's worthwhile in your case.
You might want to look at apc php.net/apc