The Developer Day | Staying Curious

TAG | framework

Mar/10

10

Zend Framework Advanced Error Controller

The default Zend Framework Error Controller generated by Zend_Tool is quite simple. It displays a simple error message, sets a response status and if exception display is enabled in the current environment, an exception message, stack trace and request variables are displayed.

While such a standard error controller may work well for many web applications it may not be suitable for everyone. The main disadvantage of the default error controller is that it does not notify developers of the errors that occurred and instead silently logs them. Many enterprise web applications will find this unacceptable and will try to implement their means of solving the issue. In this post I’ll try to show how a more advanced Zend Framework error controller could be implemented to help developers tackle errors quickly.

class ErrorController extends Zend_Controller_Action
{
    private $_notifier;
    private $_error;
    private $_environment;

    public function init()
    {
        parent::init();

        $bootstrap = $this->getInvokeArg('bootstrap');

        $environment = $bootstrap->getEnvironment();
        $error = $this->_getParam('error_handler');
        $mailer = new Zend_Mail();
        $session = new Zend_Session_Namespace();
        $database = $bootstrap->getResource('Database');
        $profiler = $database->getProfiler();

        $this->_notifier = new Application_Service_Notifier_Error(
            $environment,
            $error,
            $mailer,
            $session,
            $profiler,
            $_SERVER
        );

        $this->_error = $error;
        $this->_environment = $environment;
   }

    public function errorAction()
    {
        switch ($this->_error->type) {
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
                $this->getResponse()->setHttpResponseCode(404);
                $this->view->message = 'Page not found';
                break;

            default:
                $this->getResponse()->setHttpResponseCode(500);
                $this->_applicationError();
                break;
        }

        // Log exception, if logger available
        if ($log = $this->_getLog()) {
            $log->crit($this->view->message, $this->_error->exception);
        }
    }

    private function _applicationError()
    {
        $fullMessage = $this->_notifier->getFullErrorMessage();
        $shortMessage = $this->_notifier->getShortErrorMessage();

        switch ($this->_environment) {
            case 'live':
                $this->view->message = $shortMessage;
                break;
            case 'test':
                $this->_helper->layout->setLayout('blank');
                $this->_helper->viewRenderer->setNoRender();

                $this->getResponse()->appendBody($shortMessage);
                break;
            default:
                $this->view->message = nl2br($fullMessage);
        }

        $this->_notifier->notify();
    }

    private function _getLog()
    {
        $bootstrap = $this->getInvokeArg('bootstrap');
        if (!$bootstrap->hasPluginResource('Log')) {
            return false;
        }
        $log = $bootstrap->getResource('Log');
        return $log;
    }
}

The modified error controller is aware of the environment it is running in. It’s likely that depending on the environment you would want to display different layouts with different information. For example while debugging Zend Controller Tests you may want to reduce the amount of HTML appearing in your terminal screen by disabling the layout while running in the test environment. You’ll also notice the Application_Service_Notifier_Error class dependency. This class is responsible for deciding whether to send an email to the developers and gathers potentially helpful information from different sources. You’ll also notice how the dependencies for the notifier are instantiated. It can be done in different ways using dependency injection frameworks, using bootstrap resources and so on. It’s up to you to decide what fits your application better.

class Application_Service_Notifier_Error
{
    protected $_environment;
    protected $_mailer;
    protected $_session;
    protected $_error;
    protected $_profiler;

    public function __construct(
        $environment,
        ArrayObject $error,
        Zend_Mail $mailer,
        Zend_Session_Namespace $session,
        Zend_Db_Profiler $profiler,
        Array $server)
    {
        $this->_environment = $environment;
        $this->_mailer = $mailer;
        $this->_error = $error;
        $this->_session = $session;
        $this->_profiler = $profiler;
        $this->_server = $server;
    }

    public function getFullErrorMessage()
    {
        $message = '';

        if (!empty($this->_server['SERVER_ADDR'])) {
            $message .= "Server IP: " . $this->_server['SERVER_ADDR'] . "\n";
        }

        if (!empty($this->_server['HTTP_USER_AGENT'])) {
            $message .= "User agent: " . $this->_server['HTTP_USER_AGENT'] . "\n";
        }

        if (!empty($this->_server['HTTP_X_REQUESTED_WITH'])) {
            $message .= "Request type: " . $this->_server['HTTP_X_REQUESTED_WITH'] . "\n";
        }

        $message .= "Server time: " . date("Y-m-d H:i:s") . "\n";
        $message .= "RequestURI: " . $this->_error->request->getRequestUri() . "\n";

        if (!empty($this->_server['HTTP_REFERER'])) {
            $message .= "Referer: " . $this->_server['HTTP_REFERER'] . "\n";
        }

        $message .= "Message: " . $this->_error->exception->getMessage() . "\n\n";
        $message .= "Trace:\n" . $this->_error->exception->getTraceAsString() . "\n\n";
        $message .= "Request data: " . var_export($this->_error->request->getParams(), true) . "\n\n";

        $it = $this->_session->getIterator();

        $message .= "Session data:\n\n";
        foreach ($it as $key => $value) {
            $message .= $key . ": " . var_export($value, true) . "\n";
        }
        $message .= "\n";

        $query = $this->_profiler->getLastQueryProfile()->getQuery();
        $queryParams = $this->_profiler->getLastQueryProfile()->getQueryParams();

        $message .= "Last database query: " . $query . "\n\n";
        $message .= "Last database query params: " . var_export($queryParams, true) . "\n\n";

        return $message;
    }

    public function getShortErrorMessage()
    {
        $message = '';

        switch ($this->_environment) {
            case 'live':
                $message .= "It seems you have just encountered an unknown issue.";
                $message .= "Our team has been notified and will deal with the problem as soon as possible.";
                break;
            default:
                $message .= "Message: " . $this->_error->exception->getMessage() . "\n\n";
                $message .= "Trace:\n" . $this->_error->exception->getTraceAsString() . "\n\n";
        }

        return $message;
    }

    public function notify()
    {
        if (!in_array($this->_environment, array('live', 'stage'))) {
            return false;
        }

        $this->_mailer->setFrom('do-not-reply@domain.com');
        $this->_mailer->setSubject("Exception on Application");
        $this->_mailer->setBodyText($this->getFullErrorMessage());
        $this->_mailer->addTo('alerts@domain.com');

        return $this->_mailer->send();
    }
}

This class provides an extensive report providing helpful details in what state the application was when an exception occurred. What’s the IP address of the server (maybe the application is distributed on many servers), what was the time, was it an AJAX request, what was user’s session data, request data.

One of the nice things to have is to be able to tell what was the last database query executed. This is especially useful if some dynamic database query fails or someone is trying to make an SQL injection. The easiest way to achieve this is to use a Zend_Db_Profiler. But the default profiler consumes a lot of server resources and should not be enabled on production environments. To work around this we use a custom dummy profiler that does no profiling at all and just stores the last query information in memory.

class Application_Db_Profiler extends Zend_Db_Profiler
{
    protected $_lastQueryText;
    protected $_lastQueryType;

    public function queryStart($queryText, $queryType = null)
    {
        $this->_lastQueryText = $queryText;
        $this->_lastQueryType = $queryType;

        return null;
    }

    public function queryEnd($queryId)
    {
        return;
    }

    public function getQueryProfile($queryId)
    {
        return null;
    }

    public function getLastQueryProfile()
    {
        $queryId = parent::queryStart($this->_lastQueryText, $this->_lastQueryType);

        return parent::getLastQueryProfile();
    }
}

The custom error controller will only notify developers of errors that occur on production and stage environments to avoid spamming people with exceptions from the unstable development environment. The Application_Service_Notify_Error class is also highly testable. All the dependencies can be mocked, no global variables or constants are used. The class itself could be more refined by employing polymorphism instead of if statements but I believe it’s better to keep the example simple to make it easily understandable.

Depending on which version of the Zend Framework is being used the implementation for the custom error controller may be a little different, but the general idea is the same. In short the advanced error controller provides additional information such as session data, database queries, server variables and also is capable of notifying developers when errors occur on production or stage environments. Please let me know if this is helpful by providing feedback in the comments.

, , , , Hide

Feb/10

26

Zend Framework Escaping Entities

Zend Framework has a powerful input filtering component Zend_Filter_Input. It provides an interface to define multiple filters and validators and apply them to a collection of data. By default values returned from Zend_Filter_Input are escaped for safe HTML output. An example of such functionality:

$validators = array(
    'id' => array(
        'digits',
        'allowEmpty' => true,
    ),
    'name' => array(
        'presence' => 'required',
        new Zend_Validate_StringLength(5, 255),
    ),
    'date' => array(
        'presence' => 'required',
        new Zend_Validate_Date('d/m/Y'),
    ),
);

$filters = array(
    '*'  => 'StringTrim',
);

$input = new Zend_Filter_Input($filters, $validators, $data);

if ($input->isValid()) {
    print_r($input->getEscaped());
} else {
    print_r($input->getMessages());
}

The code above validates the $data array by checking that the id key consists only of digits or is empty, that name is present and it’s min length is 5 and max length is 255 and that date is present and it’s format is d/m/Y. The StringTrim validator removes any spaces in front and at the end of all the $data values. If the $data array is valid all escaped values are outputted and if not a generated list of error messages is presented.

Recently I’ve ran into a small problem while using Zend_Input_Filter. According to the best security practices all data coming from the user should be escaped before being outputted to the screen. This also means data coming from a database. This requires to escape every single output statement in every view. In my opinion this adds unwanted verbosity, performance overhead and a possibility to easily miss that something was not escaped in one of the views. That is why if there is a possibility I would prefer to trust the database and not worry about the data incoming from it. It may not be a very good option if data in the database is most often presented in other documents than HTML. Since all values would need to be decoded which defeats the whole purpose. Though this is rarely the case.

By default Zend_Filter_Input escapes values by using the htmlentities function. Which converts all applicable characters to HTML entities. This means that for example Danish language characters Æ Ø Å would be stored as Æ Ø Å Which means that it would take 7 bytes on average to store a single letter that otherwise could be stored using 1 – 3 bytes using UTF-8 encoding support in MySQL. This could also potentially ruin collation sorting.

To overcome this issue a very similar function htmlspecialchars could be used. It escapes only a few certain characters such as > < ” without escaping all international characters. The actual problem with Zend_Filter_Input is that it does not have an escape filter that uses htmlspecialchars. To solve the issue I’ve created a copy of HtmlEntities filter which uses htmlspecialchars function instead.

The filter can then be used like this:

$input = new Zend_Filter_Input($filters, $validators, $data);
$input->setDefaultEscapeFilter(new Company_Product_Filter_HtmlSpecialChars());

Zend_Filter_Input is a great tool to ease form validation and filtering. I would be very interested to hear from you how this problem could be solved.

, , , , , , Hide

Feb/10

20

Zend Framework Database Profiler Reporting

Zend Framework has a powerful Database Profiler component. It is remarkably simple to integrate the database profiler with the Zend Framework front controller with the use of Firefox addons FireBug and FirePHP:

// In your bootstrap file

$profiler = new Zend_Db_Profiler_Firebug('All DB Queries');
$profiler->setEnabled(true);

// Attach the profiler to your db adapter
$db->setProfiler($profiler);

Or just by enabling it in the database configuration:

$db = array(
    'type' => 'pdo_mysql',
    'host' => 'localhost',
    'dbname' => 'dbname',
    'username' => 'username',
    'password' => 'password',
    'profiler' => array(
        'enabled' => true,
        'class' => 'Zend_Db_Profiler_Firebug',
    )
);

Producing nicely formatted results:

Firebug profiler is great tool. But it requires to use Firefox and have FireBug and FirePHP addons installed. Not everyone in your organization may be Firefox users or have these addons installed. Another drawback is that sometimes queries may be quite big and complex. It’s not easy to analyse them in a Firebug window or to copy them to an editor that supports SQL highlighting.

To solve that it is possible to create a custom database profiler reporting mechanism. To output the profiler queries I’ll create a custom Zend Framework action helper:

class Company_Product_Helper_Profiler extends Zend_Controller_Action_Helper_Abstract
{
    protected $_profiler;
    protected $_view;
    protected $_config;
    protected $_db;

    public function __construct(Zend_Config $config, $db)
    {
        $this->_config = $config;
        $this->_db = $db;
    }

    public function init()
    {
        $this->_view = new Zend_View();

        parent::init();
    }

    public function postDispatch()
    {
        $this->_profiler = new Company_Product_Db_Profiler_Report($this->_db1);

        if (!$this->_isProfilerEnabled()) {
            return false;
        }

        $this->outputToScreen();
    }

    protected function _isProfilerEnabled()
    {
        if ($this->_config->environment == 'live') {
            return false;
        }

        if (!empty($_SERVER['HTTP_X_REQUESTED_WITH'])) {
            return false;
        }

        $profiler = $this->getRequest()->getParam('profiler');

        if (!empty($profiler)) {
            return true;
        }

        return false;
    }

    protected function outputToScreen()
    {
        $this->_view->headLink()->appendStylesheet('/css/highlight/default.css', 'screen');

        $this->_view->headScript()->appendFile('/js/highlight.pack.js');
        $this->_view->headScript()->appendScript('
            hljs.tabReplace = \'    \';
            hljs.initHighlightingOnLoad();
        ');

        $this->getResponse()->appendBody($this->_profiler);
    }
}

The action helper uses a post dispatch hook. The post dispatch hook is called after the Zend Framework dispatcher dispatches a request. A post dispatch hook is used to ensure that all queries have been run and to integrate the profiler with the Front Controller without changing any of the controller classes.

Action helper profiler checks to see if any profiling information should be outputted. It checks if the current configuration environment is not production to not allow unauthorized people to use the profiler. It also checks if a request is not an AJAX request, since AJAX requests may be returning JSON data structures and any additional output can break the client which sent the request. Profiler can be enabled by adding a URL query parameter ?profiler=1.

To highlight the SQL queries profiler uses a third party JavaScript highlighting library Highlight.js. On page load highlight.js finds all <code> nodes in the DOM structure, detects the programming or markup language type of the content inside them and highlights it.

The profiler action helper also uses another class to format the profiler report. The profiler report class implements an iterator interface and the __toString method allowing to use it in different ways. It could also be used to format profiler output for environments such as terminals which can’t interpret HTML.

class Company_Product_Db_Profiler_Report implements Iterator
{
    protected $_profiler;
    protected $_html = false;
    protected $_position ;

    public function __construct($db, $html = true)
    {
        $this->_profiler = $db->getProfiler();
        $this->_html = $html;
        $this->_position = 0;
        $this->_profiles = $this->_profiler->getQueryProfiles();
    }

    public function setOutputFormatToHtml($value)
    {
        $this->_html = !empty($value);
    }

    public function __toString()
    {
        $out = "";

        if ($this->_html) {
            foreach ($this->_profiles as $key => $query) {
                $out .= $this->_formatProfileAsHtml($key, $query);
            }
        } else {
            foreach ($this->_profiles as $key => $query) {
                $out .= $this->_formatProfileAsText($key, $query);
            }
        }

        return $out;
    }

    protected function _formatProfileAsHtml($key, $query)
    {
        $out = "<pre><code>{$key}. " . wordwrap($query->getQuery(), 150) . "\n\n ({$query->getElapsedSecs()} s.) </code> </pre>";
        return $out;
    }

    protected function _formatProfileAsText($key, $query)
    {
        $out = "$key. {$query->getQuery()} ({$query->getElapsedSecs()} s.)\n\n";
        return $out;
    }

    public function rewind()
    {
        $this->_position = 0;
    }

    public function current()
    {
        if ($this->_html) {
            return $this->_formatProfileAsHtml($this->_position, $this->_profiles[$this->_position]);
        } else {
            return $this->_formatProfileAsText($this->_position, $this->_profiles[$this->_position]);
        }
    }

    public function key()
    {
        return $this->_position;
    }

    public function next()
    {
        ++$this->_position;
    }

    public function valid()
    {
        return isset($this->_profiles[$this->_position]);
    }
}

To make Zend Framework aware of the profiler action helper add the following lines of code to the bootstrap file:

Zend_Controller_Action_HelperBroker::addHelper(
    new Company_Product_Helper_Profiler($config, $databaseConnection)
);

When done the output of the profiler should look something like this:

, , , , , Hide

Feb/10

12

Spring Persistence with Hibernate Review

Spring persistence with hibernate Just recently I’ve finished reading Spring Persistence with Hibernate. It’s a book about two major Java technologies Hibernate and Spring. Hibernate is a powerful object/relational persistence framework and Spring is a Java application platform that includes an MVC framework. The book is primarily meant for Spring and Hibernate developers but it may also be useful to developers who are interested in object relational mapping and advanced MVC frameworks. The topics covered in the book include object relational mapping, aspect oriented programming, inversion of control, MVC. Even though these topics are advanced the book does not require the reader to understand them beforehand. All examples are written in Java and should be understandable to anyone with a solid development background.

The book is quite lengthy consisting of more than 400 pages in total. First half of the book introduces the reader to the Hibernate persistence framework. It explains how Hibernate works in general and how it is configured. The most important chapters on Hibernate cover mapping to entities and entity collections, describe the life cycle of persistent objects, cascading operations, querying and lazy loading. The other half of the book focuses on topics such as inversion of control, aspect oriented programming also known as AOP, transaction management, Spring MVC framework and testing.

Before reading the book I didn’t have any enterprise experience with Java or it’s technologies. Working as a PHP developer I appreciate the Java community and technologies made available by it. Through many years of being exposed to enterprise application development Java community has developed powerful tools which are a great resource to developers with different development backgrounds such as me. I’ve found the book to be an excellent insight into the object relational mapping world. I’ve enjoyed reading about Spring’s AOP framework which opened my eyes in a few ways how AOP could compliment OOP. Spring IoC container which is used by Spring itself is an amazing piece of software setting new standards for other dependency injection containers out in the wild.

Even though I believe the book is a worthwhile read it can seem to be too detailed at times. For example describing all available bean factories and all other lists of available bells and whistles can seem to be dull or hardly memorable. Maybe it would be better to introduce to the idea that there are multiple factories, describe few most important ones and provide directions as to where it is possible to learn about other types of factories. The book provides many examples which is a great way to grasp the concepts quickly. Provided examples are individual pieces explaining a certain concept. It may have been better to provide examples by trying to build a real life application throughout the entire book. I believe it is a fun way to learn allowing to see how real life development issues can be solved.

I believe it’s every developer’s duty to be familiar with the latest development technologies and to know when to use them. Too many applications are written using improper tools. Object relational mapping technologies are discussed frequently and not everyone is a fan of them. The fact that Hibernate is commonly used by Java developers and .NET developers proves that persistence frameworks have their place and are worthwhile to familiarize with.

, , , , , Hide

Dec/09

9

Spring Persistence with Hibernate

Spring persistence with hibernateIt seems that I will continue reviewing books for Packt publishing. Spring Persistence with Hibernate is a book about a different development world. Spring web development framework and Hibernate persistence framework are both well known Java technologies. Even though I have little to do with Java I believe it has a great world wide community of software development experts. Not surprisingly lot’s of innovation comes from the Java world. I believe it is because Java developers know a lot more about proper design principles and coding practices than an average developer of let’s say PHP or .NET.

This book should cover such topics as getting a grip with hibernate, integrating hibernate with spring, spring IoC, spring AOP, transaction management, unit testing. I believe it will be a worthwhile read with high hopes that it will give me new ideas what I could implement or use in the PHP world.

, , , , , Hide

Zend Framework 1.8 book As I mentioned earlier guys from Packt publishing asked me to review a recently published book Zend Framework 1.8 Web Application Development. The title says it all – it’s a book about designing and developing PHP web applications using Zend framework.

This book doesn’t require the reader to be familiar with zend framework and explains all concepts in proper detail, though it will be easier to read the book if the reader is familiar with the framework and/or has experience with MVC and OOP in general. This book should be interesting to all developers who design and develop day to day web applications using MVC frameworks or not yet familiar with them as it may improve their insights towards web applications modelling, testing , optimizations and more.

Even though I am fairly familiar with the framework I found the book to be an interesting, easy read, plentiful of examples explaining the intricacies of the framework.

The first though a very important chapter teaches the concept of bootstrapping using Zend_Application and shows how to write and run a simple hello world program using controllers and views. As well it introduces the use of controller utility methods such as _getParam(), _forward(), _redirect(), action helpers, view helpers which are very valuable and a lot of developers miss them entirely. This chapter also shows the proper use of the response object which also tends to get forgotten.

The second chapter dives straight into the Front Controller pattern explaining how the framework routes, dispatches requests and responds to the client. I have never been bothered to understand the whole thing and was quite surprised to see how simple it all is. It is worth mentioning that this chapter explains in great detail how the router and various routes work and how elegantly it integrates with Zend_Config. Last the chapter covers the request object and it’s external API which provides lot’s of valuable functionality.

From the third chapter author Keith Pope starts building the main application of the entire book, the Storefront. It’s a relatively simple “real life” application that serves the purpose of being an online products catalog. This chapter shows how such an application is structured on a file system and bootstrapped and configured.  Even more the chapter covers the creation of Zend_Log and various logging writers and database profiling. Extremely valuable features that not many developers know of. If every zend framework application would start as the chapter describes I believe a lot more developers would be eager to start their IDE’s 9:00 AM straight.

Next is my personal favorite chapter – Models. Zend Framework does not have a base Model class and there’s a pretty good reason why it doesn’t. Models are specialized for a certain business task and as such it is arguably impossible to make a generic model implementation that would fit all sizes well. It then might raise a question what’s there to read about? It is my personal belief that web applications modelling has lost focus during the years by the ever growing development community. Developers got their minds focused on the next “new” thing. Let it be template engines, ORM’s, rise of active record and ruby on rails, ajax and javascript frameworks. While the majority of the models “out there” are deeply crippled. Hundreds of books were written explaining how to manage the complexity of the problem so a single chapter is a mighty challenge. I believe the author made a great choice by explaining the concept of the fat model, skinny controller, explaining the benefits composition over inheritance, data access layer separation from the business layer and my deepest respect for introducing domain model design, Martin Fowler’s book Patterns of Enterprise Application and Eric Evan’s book Domain Driven Design also known as DDD.

Next five chapters describe the implementation of the Storefront application. Each chapter highlights a major component of the framework. Use of resource autoloaders, plugins, Zend_Form, Zend_Auth, Zend_Acl. Before saying anything else it is very important to say that books rarely ever show hardcore “real life” applications as examples. Even Fowler himself likes to skip certain topics like validation in certain sections of his famous book just because they complicate things too much. This book is no exception to the rule. It’s a pretty straightforward application. There isn’t a single join to another table or a GROUP BY statement in SQL, forms implemented with Zend_Form are rather simple with little if any javascript / ajax. I found it a bit disturbing that class create other classes having both business and factory logic. One of the ugly examples was where a getPrice() method on a product model creates it’s own Taxation service which could not be mocked if that class would need to be unit tested. In most of the cases author provides injection methods for unit testing but I would argue that it does not show class dependencies explicitly which is very valuable for unit testing. Besides that I really enjoyed how the author decided to go with ACL in the domain layer. This would more often than not be implemented in the controllers making the model tightly dependent on the controllers. All in all keeping in mind that it’s a tutorial application introducing the framework I’m highly satisfied of it’s overall quality. Repeating myself. If every zend framework application would be so well written..

Another chapter worth mentioning is regarding optimizations. I was surprised to learn about such things like plugin loader cache, table gateway metadata or various Zend_Cache frontends which I have never bothered to look up. Not to mention widely known tricks using APC, stripping zend framework of all requires and setting up an optimized include path.

And last but not least again one of my favorite topics – testing. I strongly agree with Misko Hevery that test driven development is a skill. It’s definitely not easy to start or learn. One would fool himself to think otherwise.  This topic deserves many books of it’s own. I can only share from my own experience – once I started unit testing applications that I work with, I have never looked back. This chapter explains different types of testing, shows how to setup PHPUnit and provides examples of controller testing using Zend_Test. I believe this chapter deserves more attention on how to do testing with a database in mind, debugging failing controllers, avoiding complicated mocks, implementing continuous integration. But again it is worth to keep in mind that the book is about Zend Framework and not testing in general.

All in all I enjoyed reading this book. I would and will recommend it to my colleagues and friends. I hope that this hopefully not too boring review convinced you to buy the book and learn something new. Once again – big thanks to Packt Publishing for a free book. Happy reading. Over and out.

, , , , Hide

Zend Framework 1.8 bookI was recently asked by Packt Publishing to review a copy of one of their books called Zend Framework 1.8 Web Application Development book. This book is about designing, developing and deploying feature-rich PHP MVC based web applications using Zend framework. Guys from Packt Publishing were generous to send me a hard copy of the book. I owe them a thanks.

Even though I feel fairly familiar with Zend Framework I believe this book will be a great opportunity to dwell into the darker corners of the framework. The fact the Zend Framework is now at version 1.9.5 and version 2.0 is on the horizon is a bit worrying but having had a quick glimpse at the table of contents I see that some topics of particular interest to me like chapters about model design, optimizations and testing are not the ones that change at the same pace as the framework does which makes this book even more worthwhile to read.

I believe I will have a great time reading and reviewing this book.

, , , , Hide

Dec/08

31

Benchmarks battle: Yii vs. Zend Framework

While browsing through planet-php.org like every morning I’ve found this blog post promoting Yii framework. Interested I took a look at Yii benchmarks page and got really surprised.

To be honest benchmarking frameworks on a hello world application is a bit unfair. A hello world application requires very little complexity from the the framework. Zend Framework is a very powerful framework that has many strengths. A test should do something realistic. For example connecting to a database, having a configuration file, properly rendering a view, having a model to retrieve data, doing something with it, rendering a layout, trying some plugins or other components like pagination. It requires more work to do such applications, but that is a good way to do a fair benchmark.

Not related to benchmarking but I couldn’t help but notice that Yii benchamarks die in controller actions. It is not best the best thing to do. It does not allow the framework to completely shutdown and do whatever it has to do. For example executing post dispatcher methods.

The benchmarks say that Yii 1.0 is 800% faster with APC than ZendFramework 1.7.2. That is trully amazing. A huge difference. And.. I don’t really believe it is true. So let’s run the same benchmark on our own metal ;)

Let’s start with server configurations.

Yii server:

Operating System: Red Hat Enterprise Linux Server release 5.2
Web Server: Apache httpd 2.0.40
PHP: 5.2.6, any non-essential extensions are disabled
CPU: Dual Intel Xeon 3.2GHz
Main Memory: 2GB
Hard Drive: 73GB 15K RPM SCSI/SAS HDD

Our server:

Operating System: CentOS 5.2
Web Server: Apache/2.2.3 Default configuration
PHP: PHP Version 5.2.6 Default configuration + APC
CPU: Intel(R) Pentium(R) 4 CPU 3.00GHz
Main Memory: 1GB
Hard Drive: 250GB 7200 RPM SATA2

As you can see there is no big difference. Actually our server is slower :( Less CPU power, less RPMs on HDD, more not needed modules and extensions enabled, less memory.

I used the same APC settings as the Yii folks.

apc.enabled=1
apc.shm_segments=1
apc.optimization=0
apc.shm_size=32
apc.ttl=7200
apc.user_ttl=7200
apc.num_files_hint=1024
apc.mmap_file_mask=/tmp/apc.XXXXXX
apc.enable_cli=1
apc.cache_by_default=1

I’ve downloaded Yii 1.0 and zend framework 1.7.2. I’ve setup the same applications the Yii folks provide. Except I’ve removed the die and replaced it with an echo. And changed the ZF bootstrap file to work in no view renderer mode. The bootstrap file looks like this:

set_include_path(dirname(__FILE__));
require_once 'Zend/Loader.php';
Zend_Loader::registerAutoload();$front = Zend_Controller_Front::getInstance();
$front->addControllerDirectory(dirname(__FILE__)."/application/controllers", 'default');
$front->setParam('noViewRenderer', true);
$front->dispatch();

And then I ran the same AB test: “ab -t 30 -c 10 URL” as the Yii guys. I also want to note that I ran the tests a few times to warm up the APC cache. Let’s look at the results:

  • Zend Framework 1.7.2: 184 RPS (requests per second)
  • Yii 1.0: 275 RPS
  • Yii 1.0 with yiilite.php: 235 RPS

And now lets evalue these test results:

  1. Even on a slower machine ZendFramework is more than 3 times faster with APC than in the Yii benchmark. (strange)
  2. In comparison Yii is not 800% faster than ZF like shown on the Yii benchmark page.

It’s possible I’ve made a mistake somewhere. It would be nice to see more people testing this.

, , , Hide

Dec/07

29

Zend Framework pros and cons

Generally I dislike most PHP frameworks. Especially after the Ruby on Rails fashion wave after which a lot of PHP frameworks have been born with ActiveRecord implementations, scaffolding and so on. It makes you creep after watching yet another Blog development screencast in 15mins “using the best new framework”!

Not so long ago Zend Framework released a stable release and today I’ve spent my time at work watching screencasts and webinars to take a closer look at it.

And I LOVED IT :) Here’s why:

  • Whole framework is just one directory of classes that you don’t ever care about with no predefined application structure and design by default.
  • It stands behind a respectable and well known company ZEND that has a lot of to do with PHP.
  • It has an outstanding team of professional contributors with a lot of brain power and experience.
  • Lots of well developed components following actual design patterns.
  • 80% > unit test coverage
  • A useful documentation that most others are missing.
  • MVC components, controller plugins, helpers.
  • A possibility to develop a modular application where each module has it’s own views, controllers, models that can easily be removed by anyone in seconds while other frameworks force me to split MVC components to other directories and making it hard to separate from hundreds of others.
  • It does not have ActiveRecord and Scaffolding :)

Though there are some issues people might spot:

  • Zend_Controller_Helper_Abstract. Class names lack namespaces. Though there were no namespaces available while Zend Framework has been actively developed and does it really matter?
  • You need to understand a few design patterns and OOP to use full Zend framework’s potential. And that does not only requires time spent learning but also experience working with it.
  • It is big, it is heavy, it eats memory and it has a lot of includes. Though I usually tend to agree with the “hardware is cheaper than development” theory ..

All in all I find Zend Framework the best PHP framework there is. In the past I looked at CakePHP, symfony, code ignite. I’m going to give Zend Framework a try at work and implement a not so very important project with it. If it works out well I might start migrating all our frameworkless applications to it.

, , , , Hide

Find it!

Theme Design by devolux.org