Zend Framework 2.0

Zend announced back in November of 2009 that the next major release of Zend Framework was on the way. They published the new framework’s roadmap and some of the new features. The upcoming release of Zend Framework has PHP 5.3 as a requirement, as it relies on namespace support. The main changes to Zend Framework is the MVC implementation, but there are many architectural and design changes as well. Here’s a summary of the new features.

The goal of Zend Framework is to improve the overall consistency, more consistent APIs relating to constructors, options and exceptions.

  • Unified constructor. All constructors will (optionally) accept an array for options or Zend_Config object as the first argument. This allows for more flexibility to add new arguments to the constructor, have a variable number of arguments and allow “named” arguments. Additionally, it’s a good technique for allowing Dependency Injection. As part of the initiative, most components will also have a “setOptions()” method to which the options array will be passed  (and which may be used later to reset object state). Typically, this will proxy to other setters. Many components in Zend Framework 1.x already do this: Zend_Application, Zend_Form, Zend_Validate, Zend_Layout, etc. We are simply extending this paradigm to cover all components. In order to reduce code duplication, we will likely introduce a zend\Options class, which will work roughly as follows:
    namespace zend;
    class Options
    {
        public static function setOptions($object, array $options)
        {
            if (!is_object($object)) {
                return;
            }
            foreach ($options as $key => $value) {
                $method = "set" . self::_normalizeKey($key);
                if (method_exists($object, $method)) {
                    $object->$method($value);
                }
            }
        }
    
        public static function setConstructorOptions($object, $options)
        {
            if ($options instanceof Zend_Config) {
                $options = $options->toArray();
            }
            if (is_array($options)) {
                self::setOptions($object, $options);
            }
        }
    
        protected static function _normalizeKey($key)
        {
            $option = str_replace('_', ' ', strtolower($key));
            $option = str_replace(' ', '', ucwords($option));
            return $option;
        }
    }
    
    use zend\Options as Options;
    class Foo
    {
        public $bar = '';
        public $baz = '';
    
        public function __construct($options = null)
        {
            Options::setConstructorOptions($this, $options);
        }
    
        public function setOptions(array $options)
        {
            Options::setOptions($this, $options);
        }
    
        public function setBar($value)
        {
            $this->var = $value;
        }
    
        public function setBaz($value)
        {
            $this->baz = $value;
        }
    }
    
    $foo = new Foo(array('bar' => 'baz'));
    echo $foo->bar; // "baz";
    
    $foo->setOptions(array('bar' => 'boo', 'baz' => 'bat'));
    echo $foo->bar . $foo->baz; // "boobat";
    
  • Options. In Zend Framework 1.x, the various components which accept options accept a variety of formats: some expect underscore_separated keys, other expect camelCasedKeys, others expect UPPERCASEDKEYS, and some expect lowercasedkeys. This leads to confusion for many, and also leads to difficulties debugging. The goal in Zend Framework 2.0 is to standardize option keys to correct this situation. Currently, they are leaning towards all_lowercase_underscode_keys. These are human-readable, contain only valid PHP variable characters, and make for a simplified option parsing implementation. Additionally, it is trivial to translate keys to camelCase (“str_replace(‘ ‘, ”, ucwords(str_replace(‘_’, ‘ ‘, $value)))”) for purposes of overloading – and this makes it easy to document option key => class property affiliations.
  • Exceptions. Each component will have an Exception marker interface, with exceptions defined for discrete exception types thrown by the component. The concrete exceptions will either extend the global Exception class or an SPL Exception, and also implement the component Exception interface. This allows to throw appropriate SPL exceptions while retaining a common Exception type (via the marker interface). As an example:
    namespace \Foo\Bar;
    interface Exception
    {
    }
    
    class InvalidArgumentException extends \InvalidArgumentException implements Exception
    {
    }
    
    try {
        throw new InvalidArgumentException();
    }
    catch (\Foo\Bar\Exception $e) {
    }
    
  • Design By Contract. They will be altering portions of the framework to follow the concept of design by contract, and new development will follow this paradigm. At first, this will take the form of refactoring to add interfaces/refactoring interfaces to reflect actual usage.
    Interfaces make creating alternate implementation of standard classes easier, while assuring that these implementations will continue to work with the classes that consume them. In many cases currently, they offer only abstract classes, with no equivalent interfaces; in other cases, the consuming classes use methods that are not part of the interface.
    In addition to this initiative, they will be eliminating some functionality intended to add flexibility to some of the standard classes. They have found that oftentimes this functionality leads to performance overhead as well as consumes maintenance time that could be used better elsewhere in the framework. As an example, the Dispatcher has a number of methods for adding custom class -> file mappings that are largely used and which use an unnecessary number of CPU cycles; refactoring this to follow only the standard use cases would ease maintenance, while having a good, simple interface would make creating alternate implementations for custom use cases easier.
  • Elimination of most singletons. Zend Framework has often been accused of “singletonitis”. While they’re not sure if they completely agree, in most cases, the singletons they have have presented a number of problems and led to difficult test cases. Additionally, in most cases, the singletons is unwarranted. They will be refactoring to eliminate these, including in Zend_Controller_Front. In exceptional cases, they will keep them; these include global operations such as autoloading and database connections.
  • Creation of components for general-purpose, cross-functional actions. A Number of components duplicate code, and they want to push the duplication areas into discrete components that the original components may then consume. Some of these include:
    • Plugins/Helpers/Strategies (seen currently in Zend_Controller_Front, Zend_Controller_Action_Helper, Zend_View (helpers and filters), Zend_Form (validators, filters and decorators), etc). Plugin discovery and loading could benefit from a common API.
    • Decorators (seen in Zend_Form; other areas could benefit from the pattern)
    • Factories (seen currently in Zend_Db, Zend_Navigation_Page, Zend_Auth, Zend_Translate, Zend_Cache, etc)
    • Caching (seen currently in Zend_Translate, Zend_Locale, Zend_Queue, Zend_Paginator, Zend_Feed_Reader, Zend_Db_Table, etc.)
  • Usage of new language features within plugin architectures. Currently, most plugins rely on the strategy pattern, but the mechanism differs between plugins. PHP 5.3 offers some compelling alternatives that they want to explore: __invoke() and closures. Closures are less compelling as we cannot do simple type-hinting on them. __invoke() offers perhaps the simplest solution, and could become a standard API for plugins.
  • Autoload-only. They will move to using autoloading throughout the framework. This solves a number of performance issues, as well as simplifies coding dependencies (particularily exceptions).
  • Namespaces. PHP namespaces benefit frameworks and libraries more than any other code bases, and Zend Framework can benefit from it greatly, particularily with components such as Zend_Search_Lucene and Zend_Controller. However, adopting namespaces does not come without a cost: all code will need to be rewritten to define and use namespaces. This will be the single biggest BC break they introduce.
    They also plan to introduce a separate namespace for unit testing, and are currently looking at either \test\zend, \zend\test, or \testzend. This, along with per-component namespaces, will help prevent naming collisions within the test suite.
  • goto. Goto is often considered “evil”, but is invaluable when creating Finite State Machines (FSM) and parsers; usage of goto will be evaluated on a case-by-case basis. Some examples of components that could potentially benefit from such an implementation include Zend_Search_Lucene (which already implements a FSM), the MVC (more below), Zend_Ical, and Zend_Markup (though not all of these may make use of it).
  • Specifics on Plugin architecture changes

For the MVC changes, there is a great article on Pádraic Brady’s Blog.

You can also find all the information about this new version of Zend Framework on Zend’s website at http://framework.zend.com/wiki/display/ZFDEV2/Zend+Framework+2.0+Roadmap.

2 Comments

  1. Remi says:

    These are invaluable changes indeed. Can’t wait to see it in action.

  2. sgermain says:

    Not that Zend Framework 1.x is deficient in any way, but as you say, these are invaluable changes that will make developing web applications with Zend Framework even more flexible and easy. I will try to post some code samples and tutorials on how to use some of those new features!

    Stay tuned!

Leave a Reply

*