Overview
Almost every component of ZF has at least one namespaced exception class for it. Many of the components load the files containing these exceptions prematurely, even when no exception is thrown.
Since throwing an exception is the exception and not the rule, Zend_*Exception classes should only be loaded if an exception is about to be thrown. This can reduce quite allot of the overhead of loading and compiling extension classes and files on every request.
Lazy loading of exception classes can be done this way:
While the extra line of code is hard to write (isn't it?) keep in mind that it will only be executed on rare occasions, so it's worth the effort.
List of files that preload extension classes
The following is a list of all (hopefully) core ZF files that require_once Exception classes prematurely, even if no exception is thrown.
If you have fixed the file, please strike it out.
./Zend/Db/Adapter/Pdo/Ibm/Ids.php
./Zend/Db/Adapter/Pdo/Ibm/Db2.php
./Zend/Db/Adapter/Pdo/Ibm.php
./Zend/Db/Adapter/Pdo/Mysql.php
./Zend/Db/Adapter/Pdo/Mssql.php
./Zend/Db/Adapter/Pdo/Oci.php
./Zend/Db/Adapter/Pdo/Sqlite.php
./Zend/Log/Writer/Abstract.php
./Zend/Pdf/Filter/Interface.php
./Zend/Pdf/Color/Cmyk.php
./Zend/Pdf/Color/Rgb.php
./Zend/Pdf/Color/GrayScale.php
./Zend/Pdf/Color/Html.php
./Zend/Pdf/FileParser.php
./Zend/Pdf/FileParserDataSource.php
./Zend/Pdf/Cmap.php
./Zend/Pdf/Resource/Image/Png.php
./Zend/Pdf/Resource/Image/Jpeg.php
./Zend/Pdf/Resource/Image/Tiff.php
./Zend/Pdf/Resource/Font.php
./Zend/Pdf/Page.php
./Zend/Date/DateObject.php
./Zend/Feed/Builder.php
./Zend/Feed/Builder/Header/Itunes.php
./Zend/Feed/Builder/Entry.php
./Zend/Feed/Builder/Header.php
./Zend/Http/Client/Adapter/Socket.php
./Zend/Http/Client/Adapter/Proxy.php
./Zend/Http/Response.php
./Zend/Http/Client.php
./Zend/Json/Encoder.php
./Zend/Json/Decoder.php
./Zend/Mail/Part.php
./Zend/Mail/Protocol/Imap.php
./Zend/Mail/Protocol/Pop3.php
./Zend/Mail/Transport/Abstract.php
./Zend/Mail/Storage/Folder/Mbox.php
./Zend/Mail/Storage/Maildir.php
./Zend/Mail/Storage/Mbox.php
./Zend/Mail/Storage/Imap.php
./Zend/Mail/Storage/Folder.php
./Zend/Mail/Storage/Writable/Maildir.php
./Zend/Mail/Storage/Abstract.php
./Zend/Mail/Storage/Pop3.php
./Zend/Mail/Message.php
./Zend/Mime/Part.php
./Zend/Rest/Server.php
./Zend/Db.php
./Zend/Uri.php
./Zend/Mail.php
./Zend/Gdata/Kind/EventEntry.php
./Zend/Gdata/AuthSub.php
./Zend/Gdata/Calendar/Extension/Selected.php
./Zend/Gdata/Calendar/Extension/Hidden.php
./Zend/Gdata/ClientLogin.php
./Zend/Pdf.php
./Zend/Locale/Format.php
./Zend/Locale/Data.php
./Zend/Memory/Container/Movable.php
./Zend/Memory/Container/Locked.php
./Zend/Memory/Container.php
./Zend/Search/Lucene/Index/SegmentInfo.php
./Zend/Search/Lucene/Index/SegmentWriter/StreamWriter.php
./Zend/Search/Lucene/Index/SegmentWriter/DocumentWriter.php
./Zend/Search/Lucene/Index/SegmentMerger.php
./Zend/Search/Lucene/Index/SegmentInfoPriorityQueue.php
./Zend/Search/Lucene/Index/DictionaryLoader.php
./Zend/Search/Lucene/Index/SegmentWriter.php
./Zend/Search/Lucene/Search/QueryToken.php
./Zend/Search/Lucene/Search/QueryParserContext.php
./Zend/Search/Lucene/Search/QueryParserContext.php
./Zend/Search/Lucene/Search/BooleanExpressionRecognizer.php
./Zend/Search/Lucene/Search/QueryEntry.php
./Zend/Search/Lucene/Search/QueryEntry.php
./Zend/Search/Lucene/Search/QueryLexer.php
./Zend/Search/Lucene/Search/QueryLexer.php
./Zend/Search/Lucene/Search/QueryEntry/Term.php
./Zend/Search/Lucene/Search/QueryEntry/Term.php
./Zend/Search/Lucene/Search/QueryEntry/Phrase.php
./Zend/Search/Lucene/Search/QueryEntry/Phrase.php
./Zend/Search/Lucene/Search/QueryEntry/Subquery.php
./Zend/Search/Lucene/Search/QueryEntry/Subquery.php
./Zend/Search/Lucene/Search/QueryParser.php
./Zend/Search/Lucene/Search/QueryParser.php
./Zend/Search/Lucene/FSM.php
./Zend/Search/Lucene/Analysis/TokenFilter/StopWords.php
./Zend/Search/Lucene/Storage/File/Filesystem.php
./Zend/Search/Lucene/Storage/File/Memory.php
./Zend/Search/Lucene/Storage/File.php
./Zend/Search/Lucene.php
./Zend/Server/Reflection/Class.php
./Zend/Server/Reflection/ReturnValue.php
./Zend/Server/Reflection/Parameter.php
./Zend/Server/Reflection/Prototype.php
./Zend/Server/Reflection/Function/Abstract.php
./Zend/Server/Reflection.php
./Zend/Config.php
./Zend/OpenId.php
./Zend/XmlRpc/Client/ServerIntrospection.php
./Zend/XmlRpc/Request.php
./Zend/XmlRpc/Value.php
./Zend/XmlRpc/Fault.php
./Zend/XmlRpc/Server.php
./Zend/XmlRpc/Client.php
./Zend/XmlRpc/Client.php
./Zend/Console/Getopt.php
./Zend/Session.php
./Zend/Currency.php
./Zend/Controller/Action.php
./Zend/Controller/Plugin/Broker.php
./Zend/Controller/Router/Route/Module.php
./Zend/Controller/Router/Route/Interface.php
./Zend/Controller/Router/Route.php
./Zend/Controller/Request/Apache404.php
./Zend/Controller/Request/Http.php
./Zend/Controller/Front.php
./Zend/Controller/Action/Helper/Redirector.php
./Zend/Controller/Action/Helper/Abstract.php
./Zend/Controller/Action/HelperBroker.php
./Zend/Service/Audioscrobbler.php
./Zend/Service/StrikeIron/Base.php
./Zend/Service/Akismet.php
./Zend/Service/StrikeIron.php
./Zend/Service/Abstract.php
./Zend/Measure/Flow/Mole.php
./Zend/Measure/Flow/Volume.php
./Zend/Measure/Flow/Mass.php
./Zend/Measure/Binary.php
./Zend/Measure/Current.php
./Zend/Measure/Pressure.php
./Zend/Measure/Force.php
./Zend/Measure/Volume.php
./Zend/Measure/Length.php
./Zend/Measure/Temperature.php
./Zend/Measure/Angle.php
./Zend/Measure/Area.php
./Zend/Measure/Number.php
./Zend/Measure/Cooking/Volume.php
./Zend/Measure/Cooking/Weight.php
./Zend/Measure/Speed.php
./Zend/Measure/Energy.php
./Zend/Measure/Density.php
./Zend/Measure/Power.php
./Zend/Measure/Capacitance.php
./Zend/Measure/Acceleration.php
./Zend/Measure/Illumination.php
./Zend/Measure/Lightness.php
./Zend/Measure/Weight.php
./Zend/Measure/Torque.php
./Zend/Measure/Viscosity/Kinematic.php
./Zend/Measure/Viscosity/Dynamic.php
./Zend/Measure/Frequency.php
./Zend/Translate/Adapter.php
./Zend/Translate/Adapter/Array.php
./Zend/Translate/Adapter/XmlTm.php
./Zend/Translate/Adapter/Qt.php
./Zend/Translate/Adapter/Xliff.php
./Zend/Translate/Adapter/Gettext.php
./Zend/Translate/Adapter/Csv.php
./Zend/Translate/Adapter/Tbx.php
./Zend/Translate/Adapter/Tmx.php
./Zend/Date.php
./Zend/Json.php
./Zend/Memory.php
The list was generated by running the following shell commands on /trunk/library:
The rule IMHO should be that extensions are loaded before they are thrown.
As such, the exception should not be loaded from the abstract class - but from the actual implementing class, and just before the exception is thrown.
I just noticed a few files are not included in the list because they don't include the file at top level declaration though but they throw an exception.
See for example http://framework.zend.com/fisheye/browse/Zend_Framework/trunk/library/Zend/Feed/Entry/Atom.php?r1=4733&r2=7189
Yes - that's because the grep command I used looks for pre-loading Exception files.
You can find those files that inherit form files that preload exceptions by running your unit tests after fixing the listed files - you'll probably get errors from the broken files (if your tests are good enough that is...).
Another approach would be to look for classes that inherit from the class you've just fixed - and make sure it loads Exception classes before throwing.
I notice that there's a number of items on that list which show up because they're subclassing another Exception class. For example, Zend_Gdata_App_AuthException.
Do these also need to be modified? Since these subclasses should always be lazy-loaded anyway, I don't see any performance penalty based on the current implementation.
I didn't notice those - they do not need to be changed.
I tried excluding all "Exception.php" files from the search command - apparently, we have some Exception classes that do not follow that naming convention.
I guess this modified search command would work better:
ZF Home Page
Issue Tracker
SVN Browser
Wiki Dashboard
How would you handle a file like ./Zend/Service/Abstract.php ?
The exception file is required once but never used because this class is an abstract declaration intended to be extended by other Zend services.
Should the require statement simply be dropped or is there an other suggestion?