Zend Framework Hidden Gems: Zend Plumbing

December 1, 2006

Tutorials, Zend Framework

Welcome back to our third edition of the Zend Framework: Hidden Gems series of articles. In the previous two articles we discussed Zend_Cache and Zend_Config. I promised that we would move into a multi-part article on using the Zend_Db database component of the framework, however this week we will look at some of the underlying “framework” components of the Zend framework, and will start with databases next week.

Last week we discussed the features of Zend_Config. In a side discussion about how to autoload your classes, I used an example code snippet that you can add to your __autoload() function which would handle the autoloading of Zend Framework components. Zend Framework contributor, and overall PHP guru, Matthew Weier O’Phinney, commented and said that Zend Framework provides a much more concise method for doing this, and pasted in the following code:


<?php

require 'Zend.php';

function __autoload($class)
{
    Zend::loadClass($class);
}

?>

Because the file hierarchy used in Zend Framework is identical with that of both PEAR and Horde, Zend Framework’s autoload function will autoload any classes from these projects, as well as any other classes which maintain the same Classname-to-Filename convention.

Using the loadClass method as shown above is very practical if your Class filenaming convention is the same as that of Zend framework. In my projects I use a slightly different naming convention, so in my autoload, I have to check the class name and then only autoload the class if it was a zend class.

Up until this point, I haven’t discussed any of the additional helper packages that Zend Framework provides. This is because my focus has been to use as little as possible of the framework and focus as much as possible on the components. However, since we’ve gone through a couple of the packages, it’s time to introduce the top level Zend Framework Class.

Zend

The Zend class provides a suite of helper methods which are used in the Zend Framework. This is a very simple class, just a little over 350 lines, so if you haven’t taken the time to look at any Zend Framework code, this would be a good time to get your feet wet. Following are the methods that are provided:

  • loadClass
  • loadInterface
  • loadFile
  • isReadable
  • dump
  • exception
  • register
  • registry

The Zend class contains only static methods and has no external depenancies. My initial goal in this series of articles was to focus on people who were not using the Zend Framework as a framework, and show them how they could use the individual components in their own projects. As we move forward with these articles, we will use more and more of the Zend Framework, and when we discuss components such as the Controllers etc. then it will be essential that we use the top level Zend class to do class loading etc.

Whether or not you choose to use this helper package in your own projects is up to you, but regardless, this article will give you the foundation you need.

The Wrappers

We will start with some of the wrapper functions, and then move on to the very useful registry methods. One question which you might ask yourself is why you would want to use a wrapper method when it would be faster to simply use the native PHP versions of the same functions. There are several reasons. The primary reason is to be able to create a simple abstraction layer between the framework and the base language. By creating standard methods which a framework interacts with the base language gaurantees a stable API for the framework which is not dependant on PHP or the Operating system on which it is being run.

One example is the loadFile() and loadClass() methods. These are very basic operations, however by providing the API, programmers can be assured that it will work on any platform that they are using. This means that if a new development platform or operating system comes into existance that implements a revolutionary new file / directory scheme which is not compatible with anything we have today, programmer who used the API supplied to them through ZF don’t need to worry about the nuances of this new system. The Zend Framework developers will look at the new system and build support for it within the underlying classes, and the developers will not be effected by this radical change in the file access methods on the new system.

loadFile: This is a simple wrapper for PHPs include() and include_once() functions the functionality is as follows:


<?php

// PHP way
include_once('example1.php');

// ZF way

include 'Zend.php';

try {
    Zend::loadFile('example2.php', array('./inc/', './includes'), true);
} catch (Exception $e) {
    echo $e->getMessage();
}

?>

The obvious difference which you’ll see in between these two examples, is that Zend Framework’s loadFile, like all of Zend Framework utilizes PHP5′s exception handling system. This gives you the power to handle the error however you like and integrate it into your own exception based error handling system. One note to keep in mind is that if there are syntax errors in the PHP files that you are including using this helper method, this will be handled by PHP’s built in system and will raise a system error and not an exception. Because of this it is important to utilize PHP5′s error handling system to log all errors, so that you can turn display_errors off on your production servers.

The first parameter to the loadFile method, specifies the file to load. The second can either be an array or a string, and provides alternative paths for the file. If loadFile does not find the file in any of the provided paths, it will throw an exception. The documentation indicates that the class will search the include_path after it has searched the directories provided, however the underlying code does not do this at this point.

loadClass: This helper method parses the Zend Framework class names and uses loadFile to load the appropriate class.

Because Zend Framework has a predefined convention for class naming, a class such as Zend_Service_Yahoo_Image is easily translated to Zend/Service/Yahoo/Image.php which is the file in which the file exists.

loadClass() takes a second parameter, unlike loadFile() this is not an array of paths to check, but the path under which you can find the file. If you include the second parameter then the path will not be auto-discovered. For example:


<?php

include 'Zend.php';

// load Zend/Feed/Rss.php
Zend::loadClass('Zend_Feed_Rss');

// load includes/Foo_Class.php
Zend::loadClass('Foo_Class', './includes');

?>

After loading the class, loadClass() will check to ensure that the class has been loaded and then throw an exception if the file is loaded but the class does not exist. loadClass() uses loadFile() to load the file, so if you have a syntax error within your class you will get the PHP error message, not an exception.

loadInterface: This method is exactly the same as loadClass except that it loads an interface instead of a class.

Note Regarding the load* methods. These methods all rely on the loadFile method which includes a fopen() call to ensure that the file exists before loading it. As anyone who has worked on optimizing scripts can attest, filesystem calls are quite expensive. This extra call may not be an issue in your script, but if there comes a time when you need to do serious optimisation, these functions could be a good starting place. In the svn HEAD of ZF the extra fopen() has been removed and the algorithm optimized for performance.

isReadable: This is a simple wrapper for PHP’s is_readable() function. The difference between this method and PHP’s built in function, is that isReadable() searches through your include_path for the specific file. Thanks to recent changes this is no slower than the native is_readable().

dump: Every PHP programmer has implemented a dump() method in their code. This is a wrapper for var_dump, which adds <pre> tags, and beautifies the var_dump() output for either HTML or CLI output.

exception: This is a new helper method which has not been released yet, but it is interesting so I figured we might as well stay ahead of the crowd. This is a wrapper for throwing Exceptions. The usage is as follows


<?php

include 'Zend.php';

$err_code = 5;
$exception = Zend::exception('Zend_New_Exception', 'This is a sample exception', $err_code);

throw $exception;

// as opposed to the traditional way of throwing exceptions
throw new Zend_New_Exception('This is a sample exception', $err_code);

?>

Note that Zend::exception() does not throw the exception, it just does the needed sanity checking and the loading of the needed exception class, and then returns the exception to you. At this point you are able to modify the exception class before throwing the exception.

We’re done with the helper methods, let’s look at the Registry functions.

Zend Registry

Before we get into in depth discussion on how to use the Zend Registry methods, we need to discuss the registry pattern. The Registry pattern “provides a mechanism for storing data globally in a well managed fashion, helping to prevent global meltdown.” That is a quote directly out of phppattern’s interesting (although php4 based) look at the registry pattern. If you are not familiar with this pattern, then now is a good time to read both of these articles on how to use the Registry pattern with PHP.

http://www.phppatterns.com/docs/design/the_registry
http://www.patternsforphp.com/wiki/Registry

Zend’s implementation is a Singleton Registry, which removes the need for individual Zend Framework packages to implement singleton methods within them and allows them to use the global registry to maintain singleton packages.

An example:


<?php

include 'Zend.php';

Zend::loadClass('Zend_Config_Ini');

$config = new Zend_Config_Ini('./config.ini', 'database');

Zend::register('conf', $config);

?>

In this example the configuration object is being created by the Zend_Config class, and then we are storing the object within Zend’s registry. In this next example we are in an included class and we need to use the configuration that we stored in the registry.


<?php
class MyDB extends Zend_Db {

    public function factory() {
        try {
            $conf = Zend::registry('conf');
        } catch (Zend_Exception $e) {
            die($e->getMessage());
        }

        $params = array ('host'     => $conf->host,
                                'username' => $conf->username,
                                'password' => $conf->password,
                                'dbname'   => $conf->dbname);

        $db = parent::factory($conf->db_type, $options);
        return $db;
    }
}
?>

This is a very simple Template pattern that we are using to create our own application specific instance of the Zend_Db class. To configure our database we need to pull information out of the Config class. Without using the Zend Registry, we would either have to create a new instance of the Zend_Config class and load up the ini file or create a global variable to hold the configuration values.

Creating a new instance would be quite foolish since it would mean hard-coding the configuration file and the options directly into the class. This means that if at any point you choose to re-organize your configuration data (change file names, or change the format of your configuration) you will need to hunt down all the classes which reference the configuration data, and this can be problematic. Using global variables at this point simply isn’t an option.

Using the Zend Registry allows us to create one instance of our object and then share it throughout our application. Because PHP5 returns an instance of the object, any of the objects are able to modify the object and the changes will be reflected globally.

The preceding examples demonstrate how you can use the register() and the registry() methods to store and retrieve objects from the Zend registry. The final method is the simple isRegisterd() method, which accepts a string as a parameter and checks whether an object exists within the Zend registry with that name.

In Conclusion

Unfortunately, we didn’t get a chance to look Zend_Db which was our package for the week, however I hope this look at some of the Zend “plumbing” will help you get a better understanding of how the Zend Framework works. Next week we will start our look at Zend_Db and how you can use that in your platforms.

5 Responses to “Zend Framework Hidden Gems: Zend Plumbing”

  1. ryanlball Says:

    I must have missed a previous tutorial but I don’t see where Zend.php is located in the framework. Is this a supplemental class? Where is it? Thanks!

  2. grosfrais Says:

    …the main concern of my comment was about the Zend_Config’s dependency :)

  3. aaronwormus Says:

    I like ZFHG ;)

  4. aaronwormus Says:

    Thanks grosfrais, for the note.

    You are 100% correct about the illogical class naming scheme, no class ever should be named mydb :)

    In regards to requiring Zend.php, that is what this segment is about, we’ve already included the file in the top-level file so we might as well use it.

  5. grosfrais Says:

    Hi Aaron, I’d like to point two things in these issue of ZFHG:

    First, the obvious one: by using MyDB as your class’ name, you break the ZF’s naming convention, thereby breaking the Zend::loadClass magic (unless you put MyDb in MyDb.php ;)

    That said, I’d like to point the fact that by using the registry to retrieve a Zend_Config instance in MyDb::factory(), you introduce not only a dependency to the Zend’s master class (which would be ok after all), but also to Zend_Config, and to having a Zend_Config’s instance in the registry, called ‘conf’.

    I think it contradicts your will "to use as little as possible of the framework and focus as much as possible on the components" :-)