Skip to end of metadata
Go to start of metadata

<h1>Autoloading for better Performance</h1>

<p>Many discussions have come up in the recent past about how ZF should increase the libraries base throughput. One of the sugguestions that comes up is whether or not requiring the autoloader, and consequently removing calls to require_once, is a good thing.</p>

<p>This page will explore these possibilities.</p>

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Mar 27, 2008

    <p>ON BEHALF OF <ac:link><ri:user ri:username="efbiaiinzinz" /></ac:link></p>

    <p>Currently when I have looked at the code and googled around and found a case where autoloading improved memory footprint of Zend framework by 800KB and 20% speedup and after reading the coding guidelines I have a suggestion.</p>

    <p>Why not use the (spl_)autoload for entire zend framework ?</p>

    <p>So that when you need to use some other class, you don't need to<br />
    a) add require_once in top of the file<br />
    or<br />
    b) add require_once in code before using that class to make sure it is loaded for usage</p>

    <p>I know that this may improve zend framework readability if you use require_once at the top of the file or in code so it is visible that another class is being used, but shouldn't the framework be oriented on end-user/end-developer experience rather than framework-developer experience. And in case of memory footprint and cpu cycles, the lesser there are, the better it is, since more users can be served simultaneously.</p>

    <p>My suggestion would be to use spl_autoload (not to interfere with end-user's own autoloading logic) to automatically load needed classes when they are used but not yet loaded into memory.<br />
    The function is already there, only thing needed to use it would be to add few lines before each class declaration (since central class Zend will become obsolete):<br />
    require_once 'Zend/Loader.php';<br />
    Zend_Loader::registerAutoload();</p>

    <p>Or to make inclusion of Zend_Loader necessary means to use zend framework and make it register itself as autoloader by default.</p>

    <p>When spl is not available, magic function __autoload() could be used and make it call ___autoload() function for non Zend classes, to give and user option to use own loading logic.<br />
    Good idea would be to make the autoloader load only Zend classes by default perhaps to prevent auto requiring some user's php files.</p>

    <p>When autoloading is in place correctly, it would make memory usage significantly smaller and loading time also.<br />
    In lots of cases, user wants to use only few functions from class B that uses functions from class B and C and D and most probably the usage will not cover all classes (B, C and D) so including those files will just use excessive time and memory.</p>

    <p>Statically loading the files means that in cases all the files are not used, they just waste resources:<br />
    reading in php code and translating it to opcodes/class representations in memory or passing a call to optimizer extension to load opcodes from cache, when that class is not actually used during execution, is just pure memory and cpu overhead.</p>

    <p>I found some threads where autoloading usage was said to be investigated but it seems that that investigation has not gone any deeper and stopped at someone quoting "Premature optimization is the root of all evil."<br />
    In my optinion, when Zend framework is quite big already, consists of 1500 files (500 of them xml files, so 1000 php files) and is 12.4MB in size (6MB of xml files), this optimization is far from being premature, rather a long needed one.<br />
    Using autoloading would strip away all ot those require_once calls in code (thus reducing the php/optimizer calls and lesser opcodes) and in top of the files, making the refactoring and name changes easier, since instead of changing all require_once calls and the usages, only things to change will be the usages.<br />
    And the autoloading part won't make it slower as someone may think so, php should already be doing class existence checking on it's own when you do </p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[$var = new ClassName();]]></ac:plain-text-body></ac:macro>
    <p> If class is not loaded, autoloader existence is checked (if available, execute autoloader function and check class existence again), if class does not exist in memory, error is reported.<br />
    And since autoloader function usage is actually based on require/include calls, the optimizers/bytecode cachers can do their work just as well.</p>

    <p>While googling I found were some statements made by Zend team/developers that some optimizers will not be able to optimize the classes/files since then the require_once call will not be made using hard coded string 'Zend/Db.php'; but rather using a filename stored in a variable which is derivated from class name 'Zend_Db' => </p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[$name = 'Zend/Db.php'; require_once $name;.]]></ac:plain-text-body></ac:macro>
    <p>Isn't the main work of optimizers/accelerators storing the compiled bytecode of a php file and when an invocation of include(_once)/require(_once) is made, feed the compiled bytecodes directly to php instead of letting php parse the file and generate bytecodes again and again or am I mistaken somewhere ?</p>

    <p>I don't know exactly about zend optimizer, if such class loading will break some advanced optimization logic, but IMO hunting down few milliseconds and some bytes of memory compared to quite big speed and memory gains with autoload approach, the first one seems to be more af an premature optimization than the other.</p>

    <p>A good example of a generic framework end-user view:<br />
    developer has a form, file upload form, to submit images to server<br />
    dveloper knows he needs to process images, so he<br />
    a) does require_once for the image processing class at the start of the file<br />
    b) does require_once for the image processing class when file upload was successful<br />
    c) lets the autoload function handle everything and just instantiates image processing class or uses it's static method</p>

    <p>a) wastes resources (even when optimizers are used) since image processing class is loaded even when it's not actually used.<br />
    b) is almost ok, but requires user to enter a call to require_once with passing a string literal to it<br />
    c) user just invokes class and/or uses it's static methods and does not have to worry about loading it in the right place or about cases when he actually does not need to use it.</p>

    <p>Right now ZF user can choose to enable the autoloader by including 'Zend/Loader.php'; and calling Zend_Loader::registerAutoload(); but still all the hard coded require_once calls remain in the framework, forcing user unwillingly to load some classes that he won't be using and thus impacting the performance of his application.</p>

    <p>And a note from me as an autoload functionality user: When you have a class that extends another class<br />
    A.php</p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    class A {
    }
    ]]></ac:plain-text-body></ac:macro>
    <p>B.php</p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    class B extends A {
    }
    ]]></ac:plain-text-body></ac:macro>
    <p>When aoutoloader is in place, neither A nor B are loaded and you invoke following code</p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    $b = new B();
    ]]></ac:plain-text-body></ac:macro>
    <p>When your code resolves class B to B.php, includes it, PHP finds that class A existence is needed but is not loaded yet, autoload is invoked again, so you can resolve A to A.php, include it and then execution proceeds at B.php and then execution return to original location: $b = new B();</p>

    <p>When of calling require_once 'B.php'; always before dealing with class B (to ensure B is loaded and then proceed with using class B), php does some overhead.<br />
    Since PHP does not have official coding standards "filename = classname + '.php' and one class per file ", it checks the class existence always when you invoke new B(); or do B::func(); ,even if you just did require_once few lines ago. Using autoloader will invoke require_once only one time per file to load the class from there.</p>

    <p>I'm sorry if the story got a little too big and may be partially repeating itself but if you are reading this line, I hope you understood the point that I'm trying to make and that I'm trying to make zend framework even better by making it faster and making it consume just as much memory as needed. <ac:emoticon ac:name="smile" /></p>

  2. Mar 27, 2008

    <p>In my opinion, the autoloader is definetly needed to make the loading and file including as optimal as possible. Thus also improving the overall performance of the framework.</p>

    <p>For example if a main class has many functions, some of which depend on one subclass, some of which on another subclass, some need both subclasses and some even more, then with using only require_once calls, its pretty hard to get the optimal cpu usage time and memory usage for each possible codeflow.</p>

    <p>To make it as optimized as possible with require_once calls, one option is to add require_once 'subclass.php'; lines at the beginning of the function for each class that is being used in that function.<br />
    But if there is more complex logic in function (switch/case, if/else if), the most cpu and memory optimal solution would be to fully analyse the codeflow, see how many ways are there to pass through the function and add require_once calls to places where needed.<br />
    In worst case scenario, all require_once calls are put at the beginning of the file, thus including all classes that could be needed, which may also cascade to including other classes etc etc.</p>

    <p>So instead of developing the class and it's main functionality, zend framework developers end up filling the code with require_once calls to optimize their classes to full extent. Or when hasty, just put the require_once calls at the top of the file, ending up having poor loading performance for that particular class (and other classes that at some point include that class).</p>

    <p>Right now after looking at some main classes, there are some that use require_once calls to other classes in functions, some that do require_once calls for most common used classes at top of the class, some that require bunch of classes needed in all functions together at the top of the file.</p>

    <p>To prove my point of autoloading usefulness, I made a benchmark test.<br />
    The testing involves measuring memory usage difference before and after class inclusion and time it took to load the file(s) plus how many classes were loaded during including that class.<br />
    Note: since php at my computer allocates new memory to script with the size of 256KB pieces, I had to juggle around a bit in the code to get more accurate measurements, but it's not exactly 100% accurate still, so memory usage accuracy can vary some KB's from actual result. But the class loading differences still say it all.<br />
    Memory 2, Time 2 and Classes 2 mark the results of modified zend classes in what all require_once calls are stripped out (the test script included Zend_Loader and registered it as autoloader for those modified classes).<br />
    Here is the result of the tests.</p>

    <ac:macro ac:name="section"><ac:rich-text-body>
    <ac:macro ac:name="column"><ac:rich-text-body>
    <p>Class<br />
    Zend_Acl <br />
    Zend_Auth <br />
    Zend_Cache <br />
    Zend_Config <br />
    Zend_Currency <br />
    Zend_Date <br />
    Zend_Db <br />
    Zend_Debug <br />
    Zend_Exception <br />
    Zend_Feed <br />
    Zend_Filter <br />
    Zend_Form <br />
    Zend_Gdata <br />
    Zend_InfoCard <br />
    Zend_Json <br />
    Zend_Layout <br />
    Zend_Ldap <br />
    Zend_Loader <br />
    Zend_Locale <br />
    Zend_Log <br />
    Zend_Mail <br />
    Zend_Memory <br />
    Zend_Mime <br />
    Zend_OpenId <br />
    Zend_Pdf <br />
    Zend_Registry <br />
    Zend_Session <br />
    Zend_TimeSync <br />
    Zend_Translate <br />
    Zend_Uri <br />
    Zend_Validate <br />
    Zend_Version <br />
    Zend_View </p></ac:rich-text-body></ac:macro>
    <ac:macro ac:name="column"><ac:rich-text-body>
    <p>Memory<br />
    217144 <br />
    35880 <br />
    44800 <br />
    58664 <br />
    994048 <br />
    2292016 <br />
    74440 <br />
    32136 <br />
    25776 <br />
    81664 <br />
    37632 <br />
    432656 <br />
    1407488 <br />
    303224 <br />
    53240 <br />
    101096 <br />
    132712 <br />
    55472 <br />
    179488 <br />
    56064 <br />
    298208 <br />
    178944 <br />
    76768 <br />
    279752 <br />
    4276736 <br />
    48312 <br />
    228800 <br />
    2391808 <br />
    74888 <br />
    71376 <br />
    45640 <br />
    24968 <br />
    229960 </p></ac:rich-text-body></ac:macro>
    <ac:macro ac:name="column"><ac:rich-text-body>
    <p>Time<br />
    0.00779333114624 <br />
    0.000888884067536 <br />
    0.000867998600006 <br />
    0.00150343179703 <br />
    0.0154058218002 <br />
    0.0290764689446 <br />
    0.00179680585861 <br />
    0.000706338882446 <br />
    0.000574767589569 <br />
    0.00136516094208 <br />
    0.00138756036758 <br />
    0.0061589717865 <br />
    0.0578015804291 <br />
    0.0129796028137 <br />
    0.00194305181503 <br />
    0.00158960819244 <br />
    0.00200163125992 <br />
    0.00100400447845 <br />
    0.00282403230667 <br />
    0.00207567214966 <br />
    0.00878624916077 <br />
    0.0106440067291 <br />
    0.00111131668091 <br />
    0.00524481534958 <br />
    0.188408219814 <br />
    0.000896847248077 <br />
    0.00573091506958 <br />
    0.0316094994545 <br />
    0.00167950391769 <br />
    0.00167976617813 <br />
    0.00141180753708 <br />
    0.000612783432007 <br />
    0.00451095104218 </p></ac:rich-text-body></ac:macro>
    <ac:macro ac:name="column"><ac:rich-text-body>
    <p>Classes<br />
    2 <br />
    1 <br />
    1 <br />
    1 <br />
    4 <br />
    6 <br />
    2 <br />
    1 <br />
    1 <br />
    1 <br />
    1 <br />
    1 <br />
    49 <br />
    13 <br />
    3 <br />
    1 <br />
    1 <br />
    1 <br />
    1 <br />
    2 <br />
    7 <br />
    10 <br />
    1 <br />
    4 <br />
    92 <br />
    1 <br />
    3 <br />
    10 <br />
    2 <br />
    2 <br />
    1 <br />
    1 <br />
    3 </p></ac:rich-text-body></ac:macro>
    <ac:macro ac:name="column"><ac:rich-text-body>
    <p>Memory 2<br />
    175792 <br />
    35584 <br />
    43000 <br />
    58112 <br />
    119288 <br />
    1484256 <br />
    40304 <br />
    32064 <br />
    25792 <br />
    80432 <br />
    37504 <br />
    430656 <br />
    167480 <br />
    95784 <br />
    45272 <br />
    99776 <br />
    130176 <br />
    22072 <br />
    179416 <br />
    47432 <br />
    144408 <br />
    29440 <br />
    76544 <br />
    155392 <br />
    150560 <br />
    47768 <br />
    147824 <br />
    59920 <br />
    40704 <br />
    37168 <br />
    45616 <br />
    24856 <br />
    193928 </p></ac:rich-text-body></ac:macro>
    <ac:macro ac:name="column"><ac:rich-text-body>
    <p>Time 2<br />
    0.00287226438522 <br />
    0.000882363319397 <br />
    0.000876367092133 <br />
    0.00122495889664 <br />
    0.00192857980728 <br />
    0.0166901230812 <br />
    0.00090137720108 <br />
    0.000702261924744 <br />
    0.000592076778412 <br />
    0.00136638879776 <br />
    0.00144976377487 <br />
    0.00612609386444 <br />
    0.00298472642899 <br />
    0.00150204896927 <br />
    0.000940155982971 <br />
    0.00157755613327 <br />
    0.00203181505203 <br />
    0.000476968288422 <br />
    0.00284558534622 <br />
    0.000866568088532 <br />
    0.00268739461899 <br />
    0.00063613653183 <br />
    0.00114185810089 <br />
    0.0022469162941 <br />
    0.0023389339447 <br />
    0.000974488258362 <br />
    0.00274518728256 <br />
    0.00105427503586 <br />
    0.000808656215668 <br />
    0.000772392749786 <br />
    0.00143865346909 <br />
    0.000623285770416 <br />
    0.00358047485351 </p></ac:rich-text-body></ac:macro>
    <ac:macro ac:name="column"><ac:rich-text-body>
    <p>Classes 2<br />
    1 <br />
    1 <br />
    1 <br />
    1 <br />
    1 <br />
    2 <br />
    1 <br />
    1 <br />
    1 <br />
    1 <br />
    1 <br />
    1 <br />
    2 <br />
    1 <br />
    1 <br />
    1 <br />
    1 <br />
    0 <br />
    1 <br />
    1 <br />
    2 <br />
    1 <br />
    1 <br />
    1 <br />
    1 <br />
    1 <br />
    2 <br />
    1 <br />
    1 <br />
    1 <br />
    1 <br />
    1 <br />
    2 </p></ac:rich-text-body></ac:macro>
    <ac:macro ac:name="column"><ac:rich-text-body>
    <p>Memory improvement<br />
    19% <br />
    1% <br />
    4% <br />
    1% <br />
    88% <br />
    35% <br />
    46% <br />
    0% <br />
    -0% <br />
    2% <br />
    0% <br />
    0% <br />
    88% <br />
    68% <br />
    15% <br />
    1% <br />
    2% <br />
    60% <br />
    0% <br />
    15% <br />
    52% <br />
    84% <br />
    0% <br />
    44% <br />
    96% <br />
    1% <br />
    35% <br />
    97% <br />
    46% <br />
    48% <br />
    0% <br />
    0% <br />
    16% </p></ac:rich-text-body></ac:macro>
    <ac:macro ac:name="column"><ac:rich-text-body>
    <p>Time improvement<br />
    63% <br />
    1% <br />
    -1% <br />
    19% <br />
    87% <br />
    43% <br />
    50% <br />
    1% <br />
    -3% <br />
    -0% <br />
    -4% <br />
    1% <br />
    95% <br />
    88% <br />
    52% <br />
    1% <br />
    -2% <br />
    52% <br />
    -1% <br />
    58% <br />
    69% <br />
    94% <br />
    -3% <br />
    57% <br />
    99% <br />
    -9% <br />
    52% <br />
    97% <br />
    52% <br />
    54% <br />
    -2% <br />
    -2% <br />
    21% </p></ac:rich-text-body></ac:macro>
    <ac:macro ac:name="column"><ac:rich-text-body>
    <p>Class count improvement<br />
    50% <br />
    0% <br />
    0% <br />
    0% <br />
    75% <br />
    67% <br />
    50% <br />
    0% <br />
    0% <br />
    0% <br />
    0% <br />
    0% <br />
    96% <br />
    92% <br />
    67% <br />
    0% <br />
    0% <br />
    100%<br />
    0% <br />
    50% <br />
    71% <br />
    90% <br />
    0% <br />
    75% <br />
    99% <br />
    0% <br />
    33% <br />
    90% <br />
    50% <br />
    50% <br />
    0% <br />
    0% <br />
    33% </p></ac:rich-text-body></ac:macro></ac:rich-text-body></ac:macro>
    <p>As you can see, in more than 50% of the cases, there is quite huge loading performance improvement: both memory and time, and as seen from class difference, it all comes from how many classes were included when the main class was loaded. The less classes loaded, the less time and cpu cycles spent. And it is the same for all installations, optimizer or no optimizer, bytecode cace or no bytecode cache. The more things php has to include, the more time it takes to process it and the more memory they take up.</p>

    <p>So why the need to fill the code with require_once calls ?<br />
    When you instanciate the class or use it's static parts, php internally always checks if class is loaded and if not, calls autoloader. Doing always a require_once call at a function to make sure a class is loaded, each call to that function just duplicates the php's internal class existence checking (this time php has to check if that file was already loaded). Using autoloading, the require_once for a file will be called only once and exactly when needed, not a millisecond before. Thus giving the flexibility to load specific classes for the specific codeflow on the fly, exactly when needed, freeing the developers from having to fill code with require_once calls rather than coding the actual functionality.</p>

    <p>And if not use the public class Zend_Loader, then at least some internal autoloading class/function would still improve things a lot.</p>

    <p>I'm open to any remarks, comments and objections <ac:emoticon ac:name="smile" /></p>

  3. Mar 28, 2008

    <p>I think that your numbers are wrong.</p>

    <p>Looking at Zend_Locale you say there is a 60% improvement of Memory and 100% in Class loading when we change from require_once at autoloader.</p>

    <p>But Zend_Locale does not load any class which is not needed in the called function. How can the improvement then be 100% ????</p>

    <p>Also to mention: autoloading is not available in CLI interactive mode... this could be problematic.</p>

    1. Mar 28, 2008

      <p>If you follow the table rows correclty, you will see, that you mixed up the lines.<br />
      The line you are referring to (100% improvement) is actually Zend_Loader. And I guess your comment in the jira case about not undersanding how locale could have improved so much was also because of mixing up table lines.</p>

      <p>I'm not familiar with this wiki markup, so I did not know how exactly put the borders to that table to make that more readable. And neither were there borders in that table I posted to that jira case, so I apologize for that. So you have to be able to follow the lines correctly or if someone can repost it with a bordering, that would help too.</p>

      <p>The class count difference between before and after require_once is actually in that specific case (Zend_Loader not Zend_Locale) is indeed 100% because Zend_Loader was already included before.<br />
      The memory usage difference (that should also be 100% because class was loaded already) comes from the inaccuracy of memory measurement. I will need to test the memory measurement more thorouglly to make it more precise.</p>

      <p>But main measurements that are 100% trustworthy are the loading times and the class count difference before and after including. And they are measured as follows:</p>
      <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
      $classcount = count(get_declared_classes());
      $start = getmicrotime();
      require_once $classname;
      $end = getmicrotime();
      $classcount = count(get_declared_classes()) - $classcount;
      ]]></ac:plain-text-body></ac:macro>
      <p>Where getmicrotime is a function that returns precise current time.</p>

    2. Mar 28, 2008

      <p>I looked at the note about cli autoloading, read from php site and tested it on my machine.</p>

      <p>I tried the cli version on my machine. At first it said cannot find Zend_Loader since include path was missing .\library to let php search for files in library directory when doing require_once 'Zend/Loader.php';.</p>

      <p>I modified the include path at the top of the test script as such </p>
      <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
      //for windows
      set_include_path(get_include_path().';.\library');
      //for linux
      //set_include_path(get_include_path().':./library');
      ]]></ac:plain-text-body></ac:macro>
      <p>And voila, autoloading works as a charm. Even in CLI.</p>

      <p>Output of loading Zend_Mail:</p>
      <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
      C:\Prog\minuweb\zendtest2>c:\wamp\php\php.exe -v
      PHP 5.2.4 (cli) (built: Aug 30 2007 07:06:31)
      Copyright (c) 1997-2007 The PHP Group
      Zend Engine v2.2.0, Copyright (c) 1998-2007 Zend Technologies
      with Zend Debugger v5.2.10, Copyright (c) 1999-2007, by Zend Technologies

      C:\Prog\minuweb\zendtest2>c:\wamp\php\php.exe test.php
      memdiff=146744;classdiff=2;loadtime=0.00318598747253
      ]]></ac:plain-text-body></ac:macro>

      <p>So instead of telling users to modify the php.ini, they would just need to add their system specific set_include_path command at top of the file before zend framework usage. Which is in my opinion less obtrusive than modifying php.ini and restarting the webserver and allows such users to use zend framework who don't have access to php.ini</p>

      <p>Of course I haven't tested it on linux or on the minimal required php version for zend framework, so I'm not 100% sure this works on all platforms, I have to test it on linux system also and get the minimal possible version too to verify it works on all versions and opsystems (I have a hunch it will work, but better to test than assume). Everyone can have a go with following code:</p>
      <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
      //for windows
      set_include_path(get_include_path().';.\library');
      //for linux
      //set_include_path(get_include_path().':./library');
      require_once 'Zend/Loader.php';
      Zend_Loader::registerAutoload();
      require_once 'Zend/Mail.php';
      ]]></ac:plain-text-body></ac:macro>
      <p>to see if it works on your current system with cli.</p>

      1. Mar 28, 2008

        <p>Tested the autolaoding with setting include path in code for php cli on a fedora system, php 5.2.4 version, worked nicely also. With __autoload and also with spl_autoload_register also.</p>

        <p>I downloaded 5.1.4 for windows also, gues what, autoloading works just fine. And so should it work for linux version also, so the cli is no obstacle at all. There is a remark that autoloading is broken yes on php page, but as tested, it actually does work correctly.<br />
        So CLI and CGI versions both work just fine with autoloading, as long as set_include_path is being used correctly.</p>

        1. Mar 29, 2008

          <p>You don't have to persuade me <ac:emoticon ac:name="wink" /><br />
          This is a decission which have to be done by the whole dev-team.</p>

          <p>There was a reason in past why the decission was made NOT to support instant autoloading. Maybe because of some problems, or of the reason that components must be usable standalone. I don't know.</p>

          <p>I just say that your measured values have to be handled with precaution because they are not accurate enough.</p>

          1. Mar 29, 2008

            <p>Memory usage is the most inaccurate one (give or take up to 20KB but still better that using 256KB blocks difference given by get_memory_usage), but the class loading time and count of class declarations in memory are very accurate.</p>

            <p>The absolute class loading time may depend on exact system: computer cpu load and memory load, optimizers/caches used, cli or apache php module etc.<br />
            But the loading times improvement percentage remains roughly the same, the less calls done to load classes to memory and less unused classes loaded, the better performance improvement.</p>

            <p>I read about the spl_autoload_register and it was introduced in PHP 5.1 and I guess that that was the reason at some time ago for not using autoloading, since at some time zend framefork was meant to be 5.0 compatible.<br />
            But since the PHP version requirement was lifted to 5.1.4 I guess it should be quite safe now to use it.</p>

            <p>I see what you mean about keeping classes standalone, it would ultimately be nice if every class would stick only to it's subclasses thus keeping things staightforward and localized to each class.<br />
            But that would also mean lots of code duplicating.<br />
            When doing search for Zend_Loader in zend framework, 47 classes (some main classes, some subclasses) are currently using Zend_Loader already and there are more between-class dependencies than just Zend_Loader.</p>

            <p>So in my opinion, some central zend classloader (that autoloads ONLY zend classes) approach is definitely better than not having such a thing at all.<br />
            Users classes would still remain being not autoloaded unless users wants them to be (through Zend_Loader), but overall performance of framework would improve a lot.</p>

            <p>And currently I don't see any other way to get such a performance gain without autoloading or without hindering the end-user experience, since although you can fill the class functions with require_once calls in appropriate places to improve class loading, the end-user still needs to have all needed subclasses available. For example to create a pdf, many subclasses are needed by the user to put images and text into the pdf, but loading all subclasses at once means lots of time for loading and lots of unneeded classes being loaded just in case user or the code itself might need them.</p>

            <p>I hope that dev-team will decide on using autoloading since I'd hate to be and remain to be the only one using such an optimized version of zend framework. <ac:emoticon ac:name="smile" /></p>

          2. Jul 28, 2008

            <p>The reason why we do not use autoloading by default currently is that, prior to PHP 5.2.1, autoloading had really poor performance when using an opcode cache. The 5.2 series introduced a realpath stat cache, which has made it possible for opcode caches to properly cache class definitions from autloading.</p>

            <p>We fully plan to have autoloading by default with version 2.0 of ZF.</p>

            1. Jul 28, 2008

              <p>Nice to hear, looking forward to 2.0 then <ac:emoticon ac:name="smile" />, so I won't need to patch all the files for every release to make performance improvements.</p>

              <p>Until then, performance hungry users will need to patch the files on their own.</p>

              <p>Or is there some place where I can put up the modified versions of ZF that make use of the autoloading and have the performance improvements available for users who need them ?</p>

              <p>Indrek Altpere</p>

              1. Jul 28, 2008

                <p>This is the sort of thing that a build tool, such as Phing, excels at. Instead of posting a forked version of ZF that is optimized for autoloading, create a Phing task that strips out the require_once calls and publish that.</p>

  4. Mar 29, 2008

    <p>I modified the pdf class and all its subclasses, stripped all require_once calls out from them.<br />
    Then modified the demo.php to measure starting time and classcount difference before and after pdf processing.<br />
    With current released version of Zend_Pdf, time it took to process the test.pdf file and save as test2.pdf was 0.159 seconds and number of classes included was 93 (in above tests, difference with static include was 92, so one more class was being loaded at some place during execution, possibly in some function).<br />
    Time it took to load all the initial 92 classes was 0.135 seconds. So effective processing time was 0.024 seconds, only 15% of all spent time, making it averagely 0.0015 secons per class loading.</p>

    <p>With the modified version, the total time was 0.072 seconds and classes loaded were 52. Taking the previous processing time 0.024 seconds, we get that this time only 0.048 seconds was used for loading classes. 2.8 times better loading time, making average classloading time 0.00092 seconds (seems that some classes in those not loaded classes were quite big to affect the average so much).</p>

    <p>And that was all when parsing of pdf was needed, when just creating a new one, and doing the same logic for it in that pdf demo file, classes loaded dropped to 48 and time of execution to 0.056 seconds.</p>

    <p>Note: it seems that the php cli execution is somewhat faster when compared to php execution in apache when looking at loading times, possibly because apache uses another php.ini or something else. But the improvement percentages stay the same.</p>

    <p>So in conclusion, the autoloading does not just improve the time to include the main class, but makes things faster and as optimal as possible even during real executions.</p>

  5. Apr 03, 2008

    <p>Hmm, issue has been raised here for 8 days already, I have provided examples that show definite impovements in real usage, but so far it's basically been sort of monologue here except for comments made by Thomas Weidner, ending in statement that dev-team needs to be the one persuaded.</p>

    <p>So far, no tests and/or comments made by dev-team, neither for nor against the suggestion. <ac:emoticon ac:name="sad" /></p>

    <p>Is anyone except me even interested in such performance gains and optimizing the Zend Framework ? <ac:emoticon ac:name="cheeky" /></p>

    1. Apr 03, 2008

      <p>We have opened this wiki page because we see this as important.</p>

      <p>But you should also keep the reality... we are only a handfull of people and when you see at the amount of mails only from the mailinglist and other work in the background we have you should give us some days for digging for details.</p>

      <p>We will not give quick responses but we will give qualified ones... but they need a little time. <ac:emoticon ac:name="wink" /></p>

      <p>This issue will be worked on for the next release... but it is a task for the complete framework, not only the 2 parts you showed here.</p>

      <p>So please be patient for our response. <ac:emoticon ac:name="smile" /></p>

      1. Apr 03, 2008

        <p>Thank you for your reply <ac:emoticon ac:name="smile" /><br />
        I know this needs some thorugh testing and some well thought out solution: whether to use some zend specific autoloader internally or use zend_loader etc. And after all require_once calls are removed, tests need to be run to make sure everything works fine.</p>

        <p>I myself did simple regex replace that removed all require_once calls in php files for that pdf testcase and all worked fine because almost all cases are like "require_once 'Zend/Class/SubClass.pdf';"</p>

        <p>In db adapter there was some other case where class name was built together to a variable and require_once was done for classname being held in variable, but since classname was already built together, then when creating new class like new $class(); autoload was still invoked nicely.</p>

        <p>Of course the regex did not remove the comments before require_once calls and it would be better to manually check and remove needed lines to make sure too much isn't removed. Most tedious will be huge class collections like Pdf, Gdata etc. Lots of robotic work to do <ac:emoticon ac:name="cheeky" /> (reason why I used regex to get it done faster).</p>

        <p>I'm hoping to hear some nice arguments and see some other test results other than mine <ac:emoticon ac:name="smile" /></p>

        <p>Than you for your time and effort <ac:emoticon ac:name="smile" /></p>

  6. May 19, 2008

    <p>1.5 months after last comments, almost 2 months after topic creation:<br />
    Does anyone have any comments/ideas if and when and how this autoloading will be integrated into zend framework ?</p>

    <p>And if it will be integrated and has been already tested a bit, can someone show more graphs about performance improvements ?</p>

  7. Jul 25, 2008

    <p>With ZF 1.5, and spl enabled, all you have to do in your main "index.php" is :</p>

    <p>set_include_path('.' . PATH_SEPARATOR . '../library');</p>

    <p>require_once 'Zend/Loader.php';</p>

    <p>Zend_Loader::registerAutoload();</p>

    <p><ac:emoticon ac:name="smile" /></p>

    1. Jul 27, 2008

      <p>Please read the first post more thoroughlly but I'll point out some main points again just in case.</p>

      <p>In the table with results of improvement, check the "Class count improvement" column.</p>

      <p>As I have pointed out, the problem/issue is that currently zend classes are full of static includes in beginning of class files. So there are very many cascading require_once calls.<br />
      Look at the two big class-sets, Zend_Pdf and Zend_Gdata. The initial class count shows, how many classes were loaded into memory by just doing require_once 'Zend/Gdata.php'; or require_once 'Zend/Pdf.php'; in php code.<br />
      92 classes for one include (Zend_Pdf) is too much in my opinion.</p>

      <p>Just using the autoloader in index or whatever bootstrap file your application has, does not help a bit, because, it does not remove those statically written require_once calls.<br />
      It will help only to load your own classes in better way, but not zend classes.<br />
      Including Zend_Pdf would still cascade to doing require_once for 92 different classes. Taking 4MB of php memory and 0.18 seconds to load up.</p>

      <p>Zend provides autoloader, but the framework does not leverage it's benefits itself.</p>

      <p>And when you look at the post that gives more statistics for when I ran the zend provided pdf testcase, "With the modified version, the total time was 0.072 seconds and classes loaded were 52."<br />
      You can see that although the testcase uses quite different possibilities and Pdf subclasses, it only actually needs to use 52 classes instead of 92. So all other classes being loaded are pure overhead of memory and time.</p>

      <p>And only way to remove that overhead, is to remove each and every one of those require_once calls from all zend classes (except the autoloader class of course since that would need to use it to automatically load files).</p>

      <p>What bothers me, is how come I haven't seen any activity here other than one guy who is developing the Locale and some other classes.</p>

      <p>It has been exactly 4 months since I brought that issue to attention.<br />
      It took me under an hour to remove all of require_once calls in all zend php files (except autoloader).<br />
      Few more hours to gather statistics that speak for themselves.</p>

      <p>So far, no results it seems, 1.6 RC1 is out, and as I checked just now, the starting of Zend/Pdf.php contains still such 19 static require_once calls, which cacade up to 90+ require_once calls:</p>
      <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
      require_once 'Zend/Pdf/Exception.php';
      require_once 'Zend/Pdf/Page.php';
      require_once 'Zend/Pdf/Cmap.php';
      require_once 'Zend/Pdf/Font.php';
      require_once 'Zend/Pdf/Style.php';
      require_once 'Zend/Pdf/Parser.php';
      require_once 'Zend/Pdf/Trailer.php';
      require_once 'Zend/Pdf/Trailer/Generator.php';
      require_once 'Zend/Pdf/Color.php';
      require_once 'Zend/Pdf/Color/GrayScale.php';
      require_once 'Zend/Pdf/Color/Rgb.php';
      require_once 'Zend/Pdf/Color/Cmyk.php';
      require_once 'Zend/Pdf/Color/Html.php';
      require_once 'Zend/Pdf/Resource/Image.php';
      require_once 'Zend/Pdf/Image.php';
      require_once 'Zend/Pdf/Resource/Image/Jpeg.php';
      require_once 'Zend/Pdf/Resource/Image/Tiff.php';
      require_once 'Zend/Pdf/Resource/Image/Png.php';
      require_once 'Zend/Memory.php';
      ]]></ac:plain-text-body></ac:macro>

      <p>It just keeps me wondering, why this autoloading hasn't been done at all, or even discussed thoroughlly a bit more.<br />
      One reason would be because of tons of bureucracy, since this change would encompass all classes (but comparing 4 months to 1 hour to make it happen, seems like a ton of bureucracy).<br />
      Other reason could be that no one bothers to do it. Everyone is busy adding more gadgets. Sort of like adding new bumpers to a car and making it look better, while the engine still needs a little more work.</p>

      <p>If you want, I can remove those require_once calls from latest downloadable zend and make all class file include only autoloader class at the beginning. Should take 1.5 hours tops. So you can check the performance difference for yourself.</p>

      <p>Regards,<br />
      Indrek</p>

  8. Jul 27, 2008

    <p>Hello,</p>

    <p>yes you're right, it removed the requires in my bootstrap but that's all. I will try to automate the process of removing the requires in every class <ac:emoticon ac:name="smile" /></p>

    <p>It's crazy why they did not implement autoload yet.</p>

    <p>Maybe you should post a suggestion somewhere else than the wiki ? I don't know if it's read (I found this page using Google...). On features for example, people could vote for this "feature" which matters to me more than a api gadget...</p>

    <p>Julien</p>

    1. Jul 27, 2008

      <p>Voting is implemented in the issue tracker. Maybe you should post this issue there.</p>

      1. Jul 27, 2008

        <p>I did post to JIRA as a feature/improvement request on the first day I downloaded Zend framework and saw what was going on (plus one file handle bug also which has been corrected now), but my post was bumped off here, for "further discussion" (seemingly monologe mostly).</p>

        <p>Edit: if I reposted it back to JIRA (where it was bumped off in the first place), unless lots of people see it (last time seeminly no-one did who would grasp the situation in its seriousness) it is just gonna sit there for 4 or more months also, because I cannot vote for JIRA issue I myself created. Issue sat in JIRA for a week or two, then it was put here, now it's been 4 months, no progress...</p>

        <p>So far I have been doing all of the examples and explanations, basically given exact direction how to get from point 1 to point 2 and why would that be good to get there, but seems that I'm the only one actually interested in improving the performance of the core of Zend.</p>

        <p>Only one Zend guy actively commenting has been Thomas, but nothing from him lately.</p>

        <p>Makes me wonder what point does this wiki serve if noone reads it or even if reads, discards the information as trivial because the one who posted is not from Zend(or for who knows what reasons).</p>

        <p>I wonder if this improvement even ends up in framework within this year ? Because it seems I'm fighting with Zend (well, nothing to fight if noone listens) to improve their own product. If this would be a major change and bring only 2-5% speedup, sure, would be questionable to implement, but given the differences table, all pointed out black and white, implementation time 1 hour to few at tops, I just don't get it.</p>

        1. Jul 28, 2008

          <p>Just for clearification:</p>

          <p>I am NO Zend guy, I am also a (normal) community member.<br />
          And I have so much work in my sparetime with several things like I18N, the new CS or the new Zend_File_Transfer that I can not force all things which I reply to but are not my own work.</p>

          <p>I am really not the right person to blame.</p>

          <p>Greetings<br />
          Thomas, I18N Team Leader, NOT an employee of Zend</p>

          1. Jul 28, 2008

            <p>How come you were able to misunderstand me the third time during this discussion ?</p>

            <p>First it was mixup of you thinking I was blaming the size of zend framework on locale and locale xml (it was actually in JIRA case I think), when actually I was referring to in-memory size, the memory that php code and class definitions take.</p>

            <p>Second was when you thought that I was again blaming Zend_Locale by posting odd improvement statistics, when actually those statistics that seemed odd for Zend_Locale were ok for Zend_Loader which was already included before and you had just read the wrong row from the table.</p>

            <p>Now third time you think I'm blaming you for being the only one who has even bothered to write anything here in wiki.</p>

            <p>I'm glad that anyone even bothers to reply here seeing that almost no-one does so.</p>

            <p>I don't expect you to do the coding, but you could at least point some right people here at this wiki page instead of being so overly defensive about your own code and yourself when I'm not blaming Zend_Locale or you in anything, but instead suggesting huge improvement benefits for whole framework.</p>

            <p>But now to think, I do have 1 point against you, you have known the benefits and improvements of using the autoloading for Zend for like 3-4 months, you possibly know the right persons to contact about this to put the ball rolling, and yet you seem to have done nothing of sorts. Only times you seem to reply actively is when you think that I have currently been blaming you or your work.</p>

            <p>If you have been so busy for last 3-4 months so you couldn't let anyone know, could you spare me few additional minutes and give me the names or emails of the right persons so I can contact them on my own, since it seems I'm more interested in improving the Zend framework than you (seemingly very active community member) are.</p>

            <p>Note: I myself am full time Java developer who's using php from free time for extra work, plus an university student.</p>

            <p>Indrek Altpere</p>

      2. Jul 27, 2008

        <p>Hello,</p>

        <p>ok here is what I did. It took me 15 minutes !</p>

        <p>I downloaded all the files of the ZF on my PC, replaced "require_once" by "// require_once" and uploaded everything again (yes I'm not a hardcore linux user) and implemented in my bootstrap (index.php) :</p>
        <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
        include 'Zend/Loader.php';
        Zend_Loader::registerAutoload();
        ]]></ac:plain-text-body></ac:macro>
        <p>and the count of get_included_files() (in one of my controllers that does already many things) went from 71 to 49, and I got a 25% performance gain in page generation time. That is great with just one line of code <ac:emoticon ac:name="smile" /></p>

        <p>I did not do as many tests as Indrek did but that's really great for me.
        <br class="atl-forced-newline" /></p>

        <p>Julien </p>

        1. Jul 27, 2008

          <p>It took me longer since I did the replacements manually to verify what and where were removed, in conclusion, one regex replace would have done the same job, but I wanted to be sure I wouldn't break anything <ac:emoticon ac:name="wink" /></p>

          <p>Using the autoloader like that in bootstrap seems to be best option, since then users would be obligated to do only one require_once for zend classes, from there all classes would be autoloaded.</p>

          <p>No need even for require_once 'Zend/pdf.php'; anymore, just use $pdf = new Zend_Pdf($filename); and all works. Most optimal memory and time usage for class loading there is.</p>

  9. Oct 16, 2008

    <p>I strongly agree with most of the comments here - require_once is bad for performance and adds thumb overhead to your code. Usually after downloading ZF I run something like</p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    find ./ -type f -name "*.php" | xargs -l sed -i 's/require_once /\/\/ require_once /g'
    ]]></ac:plain-text-body></ac:macro>
    <p>in it's library directory. This will afair remove >3500 require_once lines - I'm obviously not using all single ZF components, but right now I didn't meet even one issue by doing so. I'm also using extended autoloaders to support ezComponents and / or Horde in combination with ZF, no problems even there.</p>

    <p>So, I would opt for:</p>
    <ul class="alternate">
    <li>making autoloader usage obligatory for ZF 2.0</li>
    <li>removing all this require_once lines from ZF code</li>
    </ul>

    <p>Cheers,<br />
    Thomas Gelf</p>

    1. Oct 16, 2008

      <p>We already plan to support both of these for 2.0. <ac:emoticon ac:name="wink" /></p>

      1. Oct 16, 2008

        <p>Great!</p>