Added by Shahar Evron, last edited by Trevor Johns on Jan 14, 2008  (view change) show comment

Labels

 

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:

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?

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 agree.

Additionally, Zend_Service_Exception is usually extended by Zend_Service_Exception child classes or used directly by Zend_Service_Abstract child classes thus I agree it could be simply removed.

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:

I've just removed all the *Exception.php entries and corrected the find command.

Oh, another false alarm: Zend_Gdata_Extension_RecurrenceException (inside Zend/Gdata/Kind/EventEntry.php) isn't actually a subclass of Zend_Exception. It's a data structure used to record <gd:recurrenceException> XML elements.