Zend Framework Components – Part 1

By: Jonathan Lebensold

Why aren’t you teaching me how to make a blogging / shopping cart application?

Because the Pragmatic Programmers did a fantastic job when they wrote their famous Rails book “Agile Web Development with Rails.” Crowds ooo-ed and aaa-ed when the rails camp wrote tutorials that described “how to make a blog in ten minutes using Rails.” PHPCake responded. They wrote a tutorial, and then people writing about Zend did the same thing.

When Stefan asked me to write about the Zend Framework, I decided I would avoid copy-able code, simply because it doesn’t re-enforce good software design. I’ve also read through many of these tutorials (most of which are excellent), however they tend to be misleading for several reasons:

- They don’t presume a complex view (with headers and footers that have dynamic logic)
- They don’t introduce core object libraries, but rather skim past them to get to the event-driven stuff (found in Zend_Controller, which I’ll cover soon)

The following is a brief summary of 4 components in the Zend Framework: Zend_Loader, Zend_Log, Zend_Config and Zend_Registry. I begin my series on the Zend Framework with these four libraries for the following reasons:

- They can be implemented independently
- They’ll be part of any serious Zend development
- They closely model pre-existing PHP functions
- They all should be handled by a general singleton pattern in your application.

Essentially, none of these components should be re-created or re-configured in any controllers, models, views or extra business objects. Furthermore, Zend_Registry can provide an entry point into re-using objects like Zend_Log and Zend_Config in a managed way (more on this later). For ASP.NET C# developers new to Zend, such a pattern exists implicitly when creating an Globals.asax.cs file.

Zend_Loader

If you’ve ever looked under the hood of any open source web applications (OpenGroupware, WordPress, the Horde Framework all come to mind), you’ll notice something that looks a little like this:

require_once(dirname(__FILE__).’/functions.php’);

By having our php application reference a general functions.php file, we centralize all our behaviour into a global functions file. Even object oriented PHP suffers from this problem when we begin implementing classes or using inheritance:

// make sure the base class is loaded
require_once (‘InheritedClass.php’);
class ChildClass extends InheritedClass
{
function __construct()
{
echo $this->foo; // will echo ‘bar’ from InheritedClass

}

}

There are many issues with this approach:
- class paths change during Refactoring
As the web application matures, its quite likely that classes will be pushed into sub-folders in order for things to remain organized. This will require massive updates to all those ‘require_once()’ functions at the beginning of class files.

- path management is decentralized
Web applications suffer from enough path issues as it is. Any sane development environment has lead us away from this (in C# and Java the ‘using’ or ‘import’ keyword, combined with namespacing allows you to load libraries needed within the scope of a class).

- require_once() encourages a linear development model
With the push towards Service-Oriented Architecture, Web Services and event-driven software design, non-linearity is becoming crucial. require_once() presumes that the programmer will handle the sequence that code will be loaded in. With event-driven systems, this burden no longer becomes trivial.

Zend_Loader to the Rescue

Zend_Loader solves all of these functions through two very simple, static methods:

- Zend_Loader::LoadClass();
- Zend_Loader::registerAutoload();

Zend applications have a simple entry point (usually index.php) where path information is either loaded or managed. Because paths need to be setup for Zend_Route (which will be discussed in future articles), Zend_Loader can use the same path setup to handle the loading of classes explicitly (using LoadClass()) or implicitly (using the registerAutoload()).

Assuming the class ‘MyClass’ is in a MyClass.php file, Zend_Loader::loadClass() will find the class through the include_paths that you’ve set in your index.php.

Using require_once():

require_once(‘../application/classes/MyClass.php’);

Using Zend_Loader::loadClass():

Zend_Loader::loadClass(‘MyClass’);

While this may appear to be a trivial difference, we’ve actually separated our infrastructure from our application design in using loadClass();

But Wait! Zend_Loader Gets Better!

Because PHP has no concept of namespacing (although this is a highly debated topic), it’s actually possible to lazy-load classes. Lazy-loading refers to letting the PHP interpreter determining which classes it needs at run-time. This means that using your favorite IDE (Integrated Development Environment), working with PHP becomes almost as effortless as C# in Visual Studio:

Integrated Development Environment

Notice the Intellisense in Eclipse (using PDT)

All that’s required is that the path information is set at the top of the page, and that ‘Zend/Loader.php’ is included into the entry point of the application:

error_reporting(E_ALL);

set_include_path('../application/classes' );
require_once "Zend/Loader.php";

Zend_Loader::registerAutoload();

// automatically load ChildClass and its base class
new ChildClass();

With registerAutoload, you can now spend more time developing and refactoring your objects and less time tracking down all those ‘require_once()’ methods of yonder.

Zend_Log
Any enterprise-class application will sooner or later have to have logging capabilities. At the very least, logs help track user flow and system behaviour. There’s a lot more to logging than most people think. Zend_Log allows you to assign priorities as a method of filtering your logs so managing different activities (such as exceptions, notifications and errors) can be handled differently.

A simple example of a file writing log would look something like this:

$writer = new Zend_Log_Writer_Stream(‘application.log’);
$logger = new Zend_Log($writer);

$priority = ZEND_LOG::INFO;
$logger->log(“this is a message” , $priority);

A note about $priority: this simply represents an integer value. The Zend Framework includes a list of pre-defined priorities, however, you can customize to your liking.

Streams
Zend_Log is best used in conjunction with Zend_Registry. The goal here would be to instantiate one or many logs with pre-defined streams, or writers. The Zend Framework includes logging streams for databases, flat files and even XML markup (through a custom formatter).

Extending Zend_Log: Writing a Custom Stream

As an experiment, I decided to extend Zend_Log to allow me to send me emails for certain events in my code. This particular example leverages two Zend components:
- Zend_Mail, for sending out emails
- Zend_Config, for isolating configuration information in a separate config.ini file

Once you have your log setup, using a log parsing tool can give you real-time feedback about your application. If you’re working under linux / bsd / mac or have cygwin installed, logs can be read from the command line using tail:

tail -f -n 200 /path/to/logfile

the -f flag enables a real-time view, and the -n tells tail that we want to see the last 200 lines, starting from the bottom.

Under Mac OS X, another tool, Console, does the same job with one extra neat feature: automatic pop-up support.

Zend_Config
If you ever plan on running development, testing and production instances of an application, configuration files need to be localized and standardized.

Zend_Config, as the name suggests, is an object for standardizing the input of configuration and the output of configuration through what is essentially an Adapter pattern. In short, Zend_Config enables developers to read configuration details that were generated from XML or through a simple YAML configuration file.

YAML configurations can look something like this:

[dev]
db.adapter = PDO_MYSQL
db.config.host = localhost
db.config.username = user_app_name_dev
db.config.password = password
db.config.dbname = app_name_dev
web.docroot = http://local.app_name/
mail.server = localhost

[prod]
db.adapter = PDO_MYSQL
db.config.host = localhost
db.config.username = user_app_name
db.config.password = password
db.config.dbname = app_name
web.docroot = http://www.app_name.com/
mail.server = localhost

Which could then be read using Zend_Config, either as an associative array:

// load configuration
$config = new Zend_Config_Ini(‘../application/config.ini’, ‘dev’); // notice the [dev] tag at the top of the YAML block?

$config_values = $config->web->toArray();
// get the document root for the application
$docroot = $config_values['docroot']);

Zend_Registry

Zend_Registry is one of the simplest components in the Zend Framework. Architecturally speaking, Zend_Registry should be created as a singleton – ensuring that’s its only instantiated once at the beginning of your application. As mentioned in the introduction, Zend_Registry can be used to handle things like Config and Database Connection objects (think Zend_Db) that need to be implemented throughout an application.

Getting / Setting Variables
Nothing could be simpler:

$registry = new Zend_Registry();

// this would be called in any classes needed
$registry = Zend_Registry::getInstance();
$registry->set(“foo”, ‘bar’);

echo $registry['foo']; // will print ‘bar’

Zend_Registry gets more interesting when you combine it with objects like Zend_Log:

// at the beginning of our application (in a singleton or in index.php at the very least)
$logger = new Zend_Log($writer);
$registry->set(‘logger’ , $logger);

// later on in our application:

$logger = Zend_Registry::get(‘logger’);
$logger->log($errorMessage,1);

Essentially, we’ve de-coupled our configuration and creation of our logging objects from what is actually being logged. You could take these examples further by wrapping up Zend_Log inside a Factory Pattern that would delegate which logging priorities get sent to which Zend_Log_Streams. With Zend_Log and Zend_Registry combined, you now have a complex, well built logging framework at your disposal anywhere in your application… even if it isn’t a sample blogging application.


This entry was posted on Friday, December 14th, 2007 at 8:21 pm and is filed under Object Oriented PHP, Zend-Framework. You can follow any responses to this entry through the RSS 2.0 feed. Both comments and pings are currently closed.

7 Responses to “Zend Framework Components – Part 1”

  1. Rob... says:

    Hi,

    It’s a minor point, but Zend_Config_Ini reads INI files, not YAML files.

    Regards,

    Rob…

  2. KillerPHP.com: Zend Framework Components – Part 1…

    On the KillerPHP.com website, there’s this new post starting off a ……

  3. David says:

    Now THIS is a useful posting. You are spot on about the way many other tutorials are “…tend to be misleading…”.

    New to frameworks or even to object oriented programming you view a “Blog in 10 Minutes” tutorial, get excited, try your hand at something more substantial (more substantial as in, actually useful… with multi-step views, templating, database usage that requires more than just the basics, some javascript, etc.) and realize that that tutorial was one step at the bottom of a steep hill with many paths winding up it.

    What you have provided is much more useful in helping explain how something works so you can make use of it in your own way. Thanks!

  4. -Rb says:

    Thank you for a great article, it looks much better in Firefox anyway!

  5. Lars Strojny says:

    That’s ini file format, not YAML. There is currently no YAML available with Zend_Config.

  6. Hey Lars,
    Thanks for pointing this out. I was thinking YAML as in “yet another markup language” but after a little wikipedia-ing, i realized that this acronym actually coresponds to a set markup language.

  7. Mike Hart says:

    Thanks for the helpful information. Coming from java/spring world into php and the Zend framework is a big help. Was looking at Zend_Config and Zend_Registry and wanted to get pointed in the right direction and your article feels like the help I needed.

Created By Stefan Mischook  |  Top of page  go to top of page