Table of Contents
- 6.1. Introduction
- 6.2. Step 1: Editing the ZFExt_Bootstrap Class
- 6.3. Step 2: Editing The Index and htaccess Files
- 6.4. Step 3: Adding The Application Configuration File
- 6.5. Step 4: Handling Setting Of Standard Component Defaults
- 6.6. Step 5: Fixing ZFExt_Bootstrap
- 6.7. Step 6: Integrating Application Configuration Into Resource Methods
- 6.8. Step 7: Optimising Autoloading Code
- 6.9. Allowing Zend_Loader_Autoload Load Namespaced Classes
- 6.10. Conclusion
Up until recently,
creating and managing the bootstrapping of a Zend Framework application
was strictly a job for the developer's imagination. This encouraged a
diverse set of practices from using monolithic procedural scripts to
classes of any structure or complexity, not to mention it doubtlessly made
designing a command line tool very difficult. With the introduction of
Zend_Application, the practice of bootstrapping now
has a common base usable in any application by any developer reinforcing a
move towards standardisation of this application need. Now if only they
had made that obvious called it
Zend_Bootstrap...
Zend_Application
was designed to be modular, customisable and configurable with a minimum
of trouble. To get us underway, since we'll be using
Zend_Application throughout the book (a lot!), lets
revisit our previous Hello World example, and rearchitect the
ZFExt_Bootstrap class. One thing I will not change
is the location of our bootstrap which will remain at
/library/ZFExt/Bootstrap.php. There's no particular
reason why we should keep it here other than the ZFExt namespace will form
the basis for our generic application library where we will keep any Zend
Framework specific custom classes for potential reuse across other
applications in the future.
The edits needed for our previous bootstrap class start off simple:
class ZFExt_Bootstrap extends Zend_Application_Bootstrap_Bootstrap{}
We will need to make
some changes to reflect what we were achieving with the original
ZFExt_Bootstrap class, but if you had no changes
your requirements for editing a bootstrap could stop here. Without any
additional code, Zend_Application can setup
everything needed using each necessary component's defaults.
Here, we're extending
Zend_Application_Bootstrap_Bootstrap which extends
Zend_Application_Bootstrap_BootstrapAbstract and
offers everything needed for a typical bootstrap setup, such as loading
Resources, dispatching through the Front Controller, and some checking to
ensure we have a proper mode of operation (i.e. production or development)
set.
As before, our
index.php file in /public is
where we first include and execute bootstrapping. We need to add a little
more complexity here. This includes setting constants to hold some
application paths, loading of a configuration to drive the bootstrapping
of our environment setup, and running the bootstrapping itself.
<?phpif (!defined('APPLICATION_PATH')) {define('APPLICATION_PATH',realpath(dirname(__FILE__) . '/../application'));}if (!defined('APPLICATION_ROOT')) {define('APPLICATION_ROOT', realpath(dirname(__FILE__) . '/..'));}if (!defined('APPLICATION_ENV')) {if (getenv('APPLICATION_ENV')) {$env = getenv('APPLICATION_ENV');} else {$env = 'production';}define('APPLICATION_ENV', $env);}set_include_path(APPLICATION_ROOT . '/library' . PATH_SEPARATOR. APPLICATION_ROOT . '/vendor' . PATH_SEPARATOR. get_include_path());require_once 'Zend/Application.php';$application = new Zend_Application(APPLICATION_ENV,APPLICATION_ROOT . '/config/application.ini');$application->bootstrap()->run();
Here we discover a
continued focus on using index.php as the location
for environmental specific setup. In index.php we
create a number of constants, setup our include_path and run the
bootstrapping process. Internally, Zend_Application
loads up our ZFExt_Bootstrap class which we will
configure in an application configuration file at
/config/application.ini to be executed. Even though
our class is empty, it still extends an Abstract class holding all the
needed methods.
One thing to note is
that these constants need to be treated with some responsibility.
Constants are global values accessible from anywhere in the application,
and like any global variable their use must be minimised and handled with
care because there is always the temptation to use them everywhere. Other
applications may not even create these constants, so any code relying on
them may not be reusable. A far better solution outside of
index.php is to keep on using
dirname() and realpath() and/or
passing in these variables via a registry object or as Front Controller
parameters accessible from your Controller actions.
In a slight departure
from the Reference Guide, I maintain index.php
according to the Zend Framework Coding Standard. It's preferably not to
use shorthand or abbreviated statement forms since they are not very
readable.
You will notice that our
index.php file now appears to default to a
"production" configuration in the absence of an environmental value
assigned to the constant APPLICATION_ENV. Obviously, we don't want to
develop using a production configuration unless we enjoy debugging
applications that mysteriously fail to display their errors, but we can
solve this by adding the necessary environmental value to our
.htaccess file:
SetEnv APPLICATION_ENV development
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ /index.php [NC,L]
This works for Apache, for other web servers please consult their documentation.
One of the main
advantages of using Zend_Application, is that once
you remove the need for custom code you can focus your efforts only on
setting up component defaults and driving the rest through configuration.
As our index.php content above suggests, we should
add a configuration file at /config/application.ini
which contains:
[production] phpSettings.display_startup_errors = 0 phpSettings.display_errors = 0 bootstrap.path = APPLICATION_ROOT "/library/ZFExt/Bootstrap.php" bootstrap.class = "ZFExt_Bootstrap" resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers" [staging : production] [testing : production] phpSettings.display_startup_errors = 1 phpSettings.display_errors = 1 resources.frontController.throwExceptions = 1 [development : production] phpSettings.display_startup_errors = 1 phpSettings.display_errors = 1 resources.frontController.throwExceptions = 1
Here, the configuration
file is split into four distinct modes: production, staging, testing and
development. All modes inherit all values from production, but may set
exceptions. For example, production settings disable display_errors while
testing and development modes ensure they are enabled. You can be sure
that Zend_Application will load the correct mode
based on the value we've given it for the APPLICATION_ENV constant set in
index.php.
The INI values used may
seem a bit strange since they show our PHP constants followed by a space
and then a double quoted relative path from the absolute path these
constants define. Zend_Application will handle the
concatenation of these two parts internally so just be aware that you can
setup paths in this manner for the component. In fact you can also setup
arrays from INI configuration files also, as we'll see in later
chapters.
Zend_Application
divides all configurations into a few categories shown on the
configuration file as prefixes. "phpSettings" refers to anything you can
set using ini_set() from PHP. "includePaths" contains
any path you want to add to the PHP include_path value (besides those set
from index.php). For example, I could use:
includePaths.foolib = APPLICATION_ROOT "/foolib/lib"
Instead I set the
include path from index.php more directly for the
standard /library and /vendor
directories but you may have others that need to be added. "bootstrap"
tells Zend_Application where our Bootstrap class is
located, and what its classname is (remember we still need our
ZFExt_Bootstrap class to change how bootstrapping
sets up some components).
Finally we have
"resource" which refers to Zend_Application
Resources.
Basically a
Zend_Application Resource is any class
Zend_Application is aware of and which it will
configure for use during bootstrapping. Above we set options for a
FrontController (the option name lowercases the first letter) to configure
the instance of Zend_Controller_Front that
Zend_Application will utilise when running our
application. For now, we're only telling
Zend_Controller_Front where to find our default
directory containing Controller classes, and whether it should throw
Exceptions when in the development or testing modes. If the configuration
convention is confusing, "controllerDirectory" maps to
Zend_Controller_Front::setControllerDirectory().
Just as if we were using an array of configuration values, using the same
convention to map array keys to the setter methods that each key
corresponds to.
In our original
ZFExt_Bootstrap class, I made a point that some
components are configured by default in a way we may find unsuitable for
use. For example, Zend_View uses a default
character encoding of ISO-8859-1 which is great, so long as you avoid
accented or multibyte characters. You can customise the default
Zend_View instance just as we did originally using
Zend_Application, and in much the same way
too!
<?phpclass ZFExt_Bootstrap extends Zend_Application_Bootstrap_Bootstrap{protected function _initView(){$view = new Zend_View();$view->setEncoding('UTF-8');$view->doctype('XHTML1_STRICT');$view->headMeta()->appendHttpEquiv('Content-Type', 'text/html;charset=utf-8');$viewRenderer =Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');$viewRenderer->setView($view);return $view;}}
Here we see that our
revised Bootstrap class can configure a Zend_View
instance by calling _initView(), something
referred to a Resource Method, since it sets up or modifies a Resource for
use. Here we are setting up a new Zend_View instance for use by the
ViewRenderer Action Helper (we'll meet Action Helpers later) where it acts
as the application's default Zend_View instance for
rendering templates. All Resource Methods to be run must follow the format
"_initResourceName()" if a protected method. You
can do the same using public methods by defining such methods in the form
"bootstrapResourceName()". Whether you use
protected or public methods is your decision.
Inside these Resource
Methods we can do a bit more by using
Zend_Application's Resource system. Basically,
Zend_Application defines a number of classes called
Resource Plugins which it uses to setup Resources as an alternative to
these simple Resource Methods.
So, what is a Resource after all this? Resource is something of a confusing term since it doesn't tell the entire story. The best way to think about it is in terms of configuring unique objects. Our application generally only requires one of each object when bootstrapping. It needs one instance of Zend_View, one instance of Zend_Controller_Front, one instance of a Router, etc. So a Resource is unique - one of a kind. The set of actions needed to create, configure and register these unique resources with Zend_Application (and the bootstrap class) come in two distinct alternative forms: Resource Methods, and Resource Plugins. Both of these follow a convention whereby the Resource they apply to is used in the method name for a Resource Method or the classname for a Resource Plugin. So, _initView() creates a Resource called View. But wait, there's also a Resource Plugin (Zend_Application_Resource_View) which may also create a Resource called View. Can we have two View Resources? The answer is no - we can have one and one only. By defining a Resource Method, we effectively override any Resource Plugin applicable to the same Resource.
A Resource Plugin is any
class which extends
Zend_Application_Resource_ResourceAbstract (or
Zend_Application_Resource_Resource) which carries
out the actual initialisation, configuration and passing of such classes
as objects to the Front Controller. A Resource Method is like a Resource
Plugin, but it's defined in the bootstrap class instead of extracted into
its own separate class. To create new objects for use during
bootstrapping, you may therefore add custom Resource Plugin classes for
this purpose or Resource Methods as a short alternative.
Of course,
Zend_Application will automatically handle some
standard classes your application may require without interference. The
Resource Plugins pre-packaged with Zend_Application
include:
| Zend_Application_Resource_Db |
| Zend_Application_Resource_FrontController |
| Zend_Application_Resource_Router |
| Zend_Application_Resource_Modules |
| Zend_Application_Resource_Navigation |
| Zend_Application_Resource_Session |
| Zend_Application_Resource_View |
| Zend_Application_Resource_Layout |
| Zend_Application_Resource_Locale |
| Zend_Application_Resource_Translate |
|
Note |
|---|---|
|
Several of these are omitted from the Reference Guide as of Zend Framework 1.9.0. Only those absolutely necessary lead to initialised Resources, so Zend_Application_Resource_Db will not immediately go and complain about a missing configuration setting because it's not run by default until you configure it. |
In our
_initView() method we were creating a replacement
or substitute Zend_View object, because
Zend_Application_Resource_View will just create a
default instance with the ISO-8859-1 character encoding and other default
options. By returning the new Zend_View instance
from _initView(),
Zend_Application will accept the replacement and
will not attempt to overwrite our changes by running
Zend_Application_Resource_View to set up a standard
default Zend_View instance with the flaws we just
corrected.
When creating a new
Resource to replace another one, we don't need to retrieve the original
one setup by the default Resource Plugin in
Zend_Application unless it's needed. Let's now add
another resource method, _initFrontController(),
which only changes some settings on an existing resource as setup by
Zend_Application_Resource_Frontcontroller.
<?phpclass ZFExt_Bootstrap extends Zend_Application_Bootstrap_Bootstrap{protected function _initView(){$view = new Zend_View();$view->setEncoding('UTF-8');$view->doctype('XHTML1_STRICT');$view->headMeta()->appendHttpEquiv('Content-Type', 'text/html;charset=utf-8');$viewRenderer =Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');$viewRenderer->setView($view);return $view;}protected function _initFrontController(){$this->bootstrap('FrontController');$front = $this->getResource('FrontController');$response = new Zend_Controller_Response_Http;$response->setHeader('Content-Type','text/html; charset=UTF-8', true);$front->setResponse($response);}}
In our original
bootstrap class, we wanted to ensure all responses defaulted to using a
Content-Type header value of "text/html; charset=UTF-8". Here, we do the
same thing by using the getResource() method to
retrieve an instance of Zend_Controller_Front
created and configured by
Zend_Application_Resource_Frontcontroller and
merely ensure it uses our own Response object instead of creating a
default one when needed. Before retrieving the FrontController Resource,
i.e. an object of type Zend_Controller_Front, we
first need to make sure Zend_Application does everything needed to create
it in the first place.
This is done by passing
the Resource Name (i.e. the final term in it's corresponding Resource
Plugin class name) to the bootstrap() method.
This forces Zend_Application to bootstrap just this
Resource. The bootstrap() method is pretty
flexible and accepts an array of Resource Names you need to have available
right now without waiting for an overall bootstrap execution.
You can take this a step further by simply replacing the default Resource Plugins. I won't cover it here since we'll be covering adding custom Resource Plugins for other objects used in our application later in the book.
For now compare the
original ZFExt_Bootstrap class with its revised
version. Less code, configuration driven, easy to work with, and
extendable via Resource Plugins. The new version is an obvious
improvement. Of course, understanding how it works is yet another hurdle
on the way to becoming a Zend Framework guru, but that's always the cost
when using more abstract classes which are nevertheless more extendable
and reusable than their monolithic alternatives.
If you just try
accessing http://helloworld.tld once more, you will notice
something odd. There is now a rather anonymous Exception being thrown
stating "Circular resource dependency detected". This occurs because we
defined a resource method _initFrontController() which conflicts with
Zend_Application_Resource_Frontcontroller when
calling bootstrap('FrontController'). Effectively we broke the rule about
Resources being unique - by attempting to use the Resource Method and
forcing the use of the Resource Plugin (which bootstrap() runs)
Zend_Application interpreted this as an attempt to create two similar
objects when we only needed one. Until we get used to thinking about
bootstrap work in terms of unique Resources, this will be a common
mistake.
This is really to
emphasis the importance of Resource Methods vs Resource Plugins (as well
as to explain this anonymous little gem when starting with
Zend_Application). You can use one or the other,
but never both with the same Resource Name at the same time. Our previous
_initView() method worked because there is no
reference to Zend_Application_Resource_View used -
our Resource Method replaces it. If we had been trying to merely change
the object generated by
Zend_Application_Resource_View using the
bootstrap() and
getResource() methods to generate and retrieve
the object, we would have had to rename the Resource Method to reflect
that we were building on the Plugin initialised Resource by creating a
modified version of it (effectively a different Resource even if the
difference was mere configuration).
This illustrates an important point - even though Zend_Application speaks about Resources, you can have a single object represented by two or more named Resources. It seems a bit silly, since at the end of the day just that one object is used regardless of how many Resource names apparently refer to it. This is really a simple contrivance though - in order to modify objects after their initial setup from Plugins or Methods (not recommended - method order is tricky), we must use a different Resource name when doing so. It doesn't need to make sense, it's just the way it works.
In
_initFrontController(), we made the mistake of
believing we could modify an existing Front Controller by retrieving it
from Zend_Application_Resource_FrontController,
without realising we were doing this in a Resource Method using the same
resource name. The moment one Resource unit tries to use another similar
named Resource unit, confusion reigns since we cannot have two objects
representing the same Resource, so Zend_Application
throws an Exception complaining about the dependency mess we tried
creating. This is a deliberate safety net.
To solve this conflict, we should rename any Resource Methods not intended to replace a Resource Plugin to something a bit more unique. In this case I've decided to prefix the existing Resource Name "FrontController" with "Modified" indicating that our Resource Method does not override a Resource Plugin, i.e. we may use the results of that Resource Plugin when it runs rather than do our own separate creation work. We also do not return the object since the Resource Plugin will register the original object for use anyway.
<?phpclass ZFExt_Bootstrap extends Zend_Application_Bootstrap_Bootstrap{protected function _initView(){$view = new Zend_View();$view->setEncoding('UTF-8');$view->doctype('XHTML1_STRICT');$view->headMeta()->appendHttpEquiv('Content-Type', 'text/html;charset=utf-8');$viewRenderer =Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');$viewRenderer->setView($view);return $view;}protected function _initModifiedFrontController(){$this->bootstrap('FrontController');$front = $this->getResource('FrontController');$response = new Zend_Controller_Response_Http;$response->setHeader('Content-Type','text/html; charset=UTF-8', true);$front->setResponse($response);}}
Now we can try http://helloworld.tld once more
without meeting any errors or exceptions.
In our application
configuration file, application.ini, we noted that we can define a
configuration for Resources using the "resources" prefix. These are
automatically used by the Zend_Application Resource
Plugins to pass options into the objects they create. So for our
FrontController Resource, we can add entries like:
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
Here the Resource name
is camel cased with the first letter in lower case, so FrontController
becomes frontController. This is not an immediate worry but we can clean
up our replacement Zend_View Resource Method a
little by ensuring any configuration options added to application.ini are
passed to the new instance. If nothing else, it also lets us push the
setting of a character encoding back into the configuration file.
<?phpclass ZFExt_Bootstrap extends Zend_Application_Bootstrap_Bootstrap{public static function autoload($class) {include str_replace('_', '/', $class) . '.php';return $class;}protected function _initView(){$options = $this->getOptions();if (isset($options['resources']['view'])) {$view = new Zend_View($options['resources']['view']);} else {$view = new Zend_View;}if (isset($options['resources']['view']['doctype'])) {$view->doctype($options['resources']['view']['doctype']);}if (isset($options['resources']['view']['contentType'])) {$view->headMeta()->appendHttpEquiv('Content-Type',$options['resources']['view']['contentType']);}$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');$viewRenderer->setView($view);return $view;}protected function _initModifiedFrontController(){$options = $this->getOptions();if (!isset($options['resources']['modifiedFrontController']['contentType'])) {return;}$this->bootstrap('FrontController');$front = $this->getResource('FrontController');$response = new Zend_Controller_Response_Http;$response->setHeader('Content-Type',$options['resources']['modifiedFrontController']['contentType'], true);$front->setResponse($response);}}
Now we can delegate
setting the character encoding and any custom configuration options that
we require to our application.ini settings.
[production] phpSettings.display_startup_errors = 0 phpSettings.display_errors = 0 bootstrap.path = APPLICATION_ROOT "/library/ZFExt/Bootstrap.php" bootstrap.class = "ZFExt_Bootstrap" resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers" resources.view.encoding = "UTF-8" resources.view.doctype = "XHTML1_STRICT" resources.view.contentType = "text/html;charset=utf-8" resources.modifiedFrontController.contentType = "text/html;charset=utf-8" [staging : production] [testing : production] phpSettings.display_startup_errors = 1 phpSettings.display_errors = 1 resources.frontController.throwExceptions = 1 [development : production] phpSettings.display_startup_errors = 1 phpSettings.display_errors = 1 resources.frontController.throwExceptions = 1
In our previous
bootstrap class, we created a custom autoload method for use which did no
file checking and simply attempted an include()
operation assuming all classnames mapped to their filenames using the PEAR
Convention. This was to avoid a method
Zend_Loader::loadClass() from the more typical
autoloader used in Zend Framework applications which does a lot of mostly
unnecessary error checking. Zend_Application is
designed to also implement autoloading using another new component,
Zend_Loader_Autoloader. Unfortunately,
Zend_Loader_Autoloader (which adds vastly improved
class autoloading features) uses the same
Zend_Loader::loadClass() method we wished to
avoid.
We can still implement
our lighter method, but not from within the bootstrap class anymore.
Rather we need to reset the
Zend_Loader_Autoloader's default loading method
before Zend_Application is initialised, and this
can only be accomplished from index.php.
<?phpif (!defined('APPLICATION_PATH')) {define('APPLICATION_PATH',realpath(dirname(__FILE__) . '/../application'));}if (!defined('APPLICATION_ROOT')) {define('APPLICATION_ROOT', realpath(dirname(__FILE__) . '/..'));}if (!defined('APPLICATION_ENV')) {if (getenv('APPLICATION_ENV')) {$env = getenv('APPLICATION_ENV');} else {$env = 'production';}define('APPLICATION_ENV', $env);}set_include_path(APPLICATION_ROOT . '/library' . PATH_SEPARATOR. APPLICATION_ROOT . '/vendor' . PATH_SEPARATOR. get_include_path());require_once 'Zend/Loader/Autoloader.php';$autoloader = Zend_Loader_Autoloader::getInstance();$autoloader->setDefaultAutoloader(create_function('$class',"include str_replace('_', '/', \$class) . '.php';"));$application = new Zend_Application(APPLICATION_ENV,APPLICATION_ROOT . '/config/application.ini');$application->bootstrap()->run();
Since we can't even
reference the bootstrap before Zend_Application is
initialised, we may instead pass
setDefaultAutoloader() an anonymous function we
create on the spot.
In PHP, where libraries are following the PEAR convention, all class names carry a common prefix commonly referred to as the "namespace" (this is not true namespacing as PHP 5.3 introduces). Our autoloader is configured to recognise class name namespaces including "Zend_" and "ZendX_". In order to load other namespaced classes, we first need to tell the autoloader that they exist. Before that we can ask the question why is this even required in the first place?
The problem with the original autoloading method was simple. It would load anything. At a glance this seems really great, it's simple, easy to understand and requires no configuration. So how is this not a good thing? The problem with the load anything behaviour is that it affords no control. Sometimes you want to make sure only certain libraries can be loaded. As an added benefit, the restriction also leads to faster lookups.
The new namespacing feature isn't perfect but that's mostly because
some libraries do not have a top level namespace prefix. For example, PEAR
components do not begin with PEAR_ so you can have
HTTP_Client, Crypt_RSA, etc. which share no
common prefix. A similar problem exists with any "root" classes, for
example HTMLPurifier uses the namespace prefix HTMLPurifer_
except for a root class in HTMLPurifier.php. In these
circumstances, you may need to return to the original behaviour where
namespaces are untracked and unrestricted using:
Zend_Loader_Autoloader::getInstance()->setFallbackAutoloader(true);
In other circumstances, a library may use its own autoloader which
you can register as an alternative to the default one implemented by
Zend_Loader_Autoloader.
$autoloader = Zend_Loader_Autoloader::getInstance();$autoloader->pushAutoloader('HTMLPurifier_Bootstrap', 'autoload');
Note that this, because of HTMLPurifier's lack of a namespace, adds a new global autoloader a bit like the fallback option makes the default autoloader operate globally without any restriction. You can pass in a namespace restricted autoloader in a similar fashion so it's only called when a specific class namespace is detected.
$autoloader = Zend_Loader_Autoloader::getInstance();$autoloader->pushAutoloader('XLib_Autoloader', 'autoload', 'XLib_');
However, let's assume for now this fallback and other autloaders are
not needed. The outcome of the new autoloader is that we need to register
all class namespaces we intend using. While we can do this in code from
index.php, it's easier to track it in our
application.ini file which makes it easy to add
namespaces as needed. Here's an example where we intend using a library
(our future application library actually) where all its class members are
prefixed with "ZFExt_". As you can probably see, you can keep adding
namespaces this way as the square brackets [], indicate they are added to
an array once the INI file is parsed by Zend_Config
(which handles all configuration parsing and loading within the
framework.
[production] phpSettings.display_startup_errors = 0 phpSettings.display_errors = 0 bootstrap.path = APPLICATION_ROOT "/library/ZFExt/Bootstrap.php" bootstrap.class = "ZFExt_Bootstrap" resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers" resources.view.encoding = "UTF-8" resources.view.doctype = "XHTML1_STRICT" resources.view.contentType = "text/html;charset=utf-8" resources.modifiedFrontController.contentType = "text/html;charset=utf-8" autoloaderNamespaces[] = "ZFExt_" [staging : production] [testing : production] phpSettings.display_startup_errors = 1 phpSettings.display_errors = 1 resources.frontController.throwExceptions = 1 [development : production] phpSettings.display_startup_errors = 1 phpSettings.display_errors = 1 resources.frontController.throwExceptions = 1
This was a quick
introduction (well, you could always learn to speed read) to
Zend_Application. As someone who has been doing my
own thing quietly I'm very happy to adopt it for use. It ensures other
developers can follow my bootstrapping process without learning a whole
new approach (from the hundreds probably existing in the wild). This is
the strength of finally having a standard approach to bootstrapping
applications.
We will see more of
Zend_Application as the book progresses since there
are lots of objects and other pieces of altered behaviour we may require
in our applications, and the bootstrap is where initialising these for use
is the best approach. On a final note, Zend_Tool
which is not covered by the book yet, uses
Zend_Application when managing applications.


