Static Factories vs Public Constructors

Normally, creating an instance of a class is done by calling new, which calls the constructor. Static factory provides a static method that returns an instance of the class. So, you are using static factory instead of the constructor. Providing a static factory method instead of a public constructor has both advantages and disadvantages.

Advantages of static factories over constructors:

  • Static factory instances have names but constructors do not.
  • Static factories can have two methods named differently but taking the same number and type of parameters.
  • Subclassing isn’t possible but inheritance isn’t always the best way to reuse code.

Disadvantages of static factories over constructors:

  • Can’t be subclassed.
  • Poor naming conventions can make it hard to know what’s going on.

Dagfinn Reiersøl wrote an interesting post about this:

I’ve never considered visibility restrictions important enough to be a major argument against those languages that have lacked them (PHP 4). So why would I be sceptical of public constructors? I got the idea after reading Joshua Kerievsky’s book Refactoring to Patterns. One of his refactorings is called Replace Constructors with Creation Methods. In Java, unlike PHP, you can have multiple constructors that are distinguished only by the number and type of arguments. That may be practical sometimes, but as Kerievsky’s example shows, it be more readable to have creation methods with different names instead. Which is what you have to anyway in PHP.

Read More: Public constructors considered harmful

Improving the performance of Zend_Controller

Zend_Controller_Router_Rewrite is the standard framework router. It takes a URI endpoint and decomposes it into parameters to determine which module, controller, and action of that controller should receive the request. Routing occurs only once, when the request is initially received and before the first controller is dispatched.

To use the router you have to instantiate it, add some user defined routes and inject it into the controller:

$routes['blog'] = new Zend_Controller_Router_Route(
	'blog/:year/:month/:day/:title/*',
	array(
		'year'       => date('Y'),
		'month'      => date('m'),
		'day'        => date('d'),
		'module'     => 'blog',
		'controller' => 'index',
		'action'     => 'archive'
	),
	array(
		'year'  => '\d+',
		'month' => '\d+',
		'day'   => '\d+',
		'title' => '([0-9a-zA-Z-]+)',
	)
);

$frontController = Zend_Controller_Front::getInstance();
$router = $frontController->getRouter();
$router->addRoutes($routes);
$frontController->dispatch();

Front Controller dispatch mechanism:

o-- Zend_Controller_Front::dispatch()
--> Zend_Controller_Front::setResponse()
--> Zend_Controller_Front::getRouter()
--> Zend_Controller_Router_Rewrite::setParams()
--> Zend_Controller_Router_Rewrite::route()

Zend_Controller_Front gets an instance of Zend_Controller_Router_Rewrite, routes the request, iterates through all the provided routes and matches its definitions to the current request URI.

The problem

The router has to load all the objects into memory, iterate through all the routes and perform regular expressions until it finds a positive match. This means that the more routes you add, the longer the router will take to process them. The problem becomes more critical when using XML or INI configuration files and a site increases in complexity and attracts more traffic.

The Solution

One of the solutions is to split the routes file into different .php or .ini files. For example, instead of loading a single file:

$frontController = Zend_Controller_Front::getInstance();
$frontController->addModuleDirectory(
	'../application/modules'
);
$config = new Zend_Config_Ini(
	'../application/config/routes/config.ini',
	'production'
);
$router = $frontController->getRouter();
$router->addConfig($config, 'routes');

You can use the My_Controller_Router_Rewrite class to set the path to the directory where all the configuration files are located:

$frontController = Zend_Controller_Front::getInstance();
$frontController->addModuleDirectory(
	'../application/modules'
);
$router = new My_Controller_Router_Rewrite();
$frontController->setRouter($router);
$router->setRoutesDirectory(
	'../application/config/routes',
	array('production', 'routes')
);

This allows the router to map the first segment of the URL path to a filename. For example, given the following URI:

http://www.zend-test.com/blog/2008/07/14/test

The router will load the blog.ini file:

application
|-- bootstrap.php
|-- config
|   `-- routes
|       |-- blog.ini
|       |-- eshop.ini
|       |-- forum.ini
|       `-- gallery.ini
|-- layouts
|   `-- main.phtml
`-- modules
    |-- blog
        |-- controllers
        |   `-- IndexController.php
        |-- models
        `-- views

Test Result Data

Zend_Controller_Router_Rewrite (4 routes)

Server Hostname:         www.zend-test.com
Document Path:           /blog/2008/07/14/test
Requests per second 1:   88.24 [#/sec]
Requests per second 2:   89.32 [#/sec]

Zend_Controller_Router_Rewrite (16 routes)

Server Hostname:         www.zend-test.com
Document Path:           /blog/2008/07/14/test
Requests per second 1:   64.45 [#/sec]
Requests per second 2:   64.61 [#/sec]

Zend_Controller_Router_Rewrite (20 routes)

Server Hostname:         www.zend-test.com
Document Path:           /blog/2008/07/14/test
Requests per second 1:   59.17 [#/sec]
Requests per second 2:   59.03 [#/sec]

Now, lets try splitting the config.ini file into separate configuration files:

MyRouter extends Zend_Controller_Router_Rewrite (4 routes)

Server Hostname:         www.zend-test.com
Document Path:           /blog/2008/07/14/test
Requests per second 1:   89.47 [#/sec]
Requests per second 2:   89.32 [#/sec]

MyRouter extends Zend_Controller_Router_Rewrite (40 routes)

Server Hostname:         www.zend-test.com
Document Path:           /blog/2008/07/14/test
Requests per second 1:   89.62 [#/sec]
Requests per second 2:   89.41 [#/sec]

Documentation

Hacking the Core of the Zend Framework

So, I’ve been hacking the core of the Zend Framework again, this time the Zend_Controller component. I spent a couple of hours monitoring the performance and tuning parameters and configuration options to minimize bottlenecks. Needless to say I am very impressed with the overall design of the component. It’s very simple, flexible and covers most of the use cases.

Performance problems typically do not become apparent until someone places an application under an increased load, so measuring the performance of an application (at design time) can help improve the scalability of the application.

The methodology I’m using:

  1. Determine the problem.
  2. Formulate a solution.
  3. Implement the solution.
  4. Analyse the results.
  5. Document everything.

Continue reading

Architecture-Oriented or Feature-Oriented?

Traditionally, there are two fundamental approaches when it comes to organising your development teams: the Architecture-Oriented approach and the Feature-Oriented approach. The first privileges teams that focus on the different architectural layers or components, whereas the second prefers to organise teams around deliverable application features.

How do you organise your development teams?

Django 1.0 will be released in early September

Django has not been updated for a long time. The most current release, 0.96, was released in March 2007. This is a very long time when you look at the roadmap of other frameworks. But guess what, all that is about to change, because Django 1.0 is only two months away! Over the next six weeks sprints will take place all over the world to help get everything done by the deadline. This document details the schedule and roadmap towards Django 1.0. Although “Release early, release often” is not as easy as it seems, I hope it becomes part of Django’s development model.

The framework is now owned by a new, nonprofit, organization. The foundation, headed by Jacob Kaplan-Moss, will now be able to accept donations to help it grow. Finally we can say that Django is in the hands of the people who care most about its long-term success.

Django 1.0 Roadmap and Schedule

Zend gets up to £3.5 million in funding from TriplePoint

Today I read the news that Zend has just received up to £3.5 million pounds from TriplePoint Capital, and that they will use the funds as needed to take advantage of market expansion opportunities as they arise. Its last round of funding, for £10 million, was raised in 2006.

TriplePoint Capital, a leading global finance company, has been a debt financing provider to Facebook, YouTube, Adify, Slide, Coskata, Ilypsa, and numerous other high profile technology companies.

Zend’s CEO Harold Goldberg said:

“The market for commercial web-based applications using PHP technologies is growing very fast in all geographies around the world”

But, why is Zend raising more money?

The easiest way to search and replace in files

The “find” command is one of the most powerful and useful Unix commands, you can use it to locate files, and then perform some type of action on the files after they’ve been located. With this capability, you can locate files using powerful search criteria, and then run any Unix command you want on the files you locate.

Find Strings

In the following example I’ll recursively search a directory for files containing the ‘test’ string and output the name of the files and the line number:

$ grep -in -e 'test' `find -type f`

This command will search in the current directory and all sub directories. All files containing the string 'test' will have their path printed to standard output:

./build/build.properties:4:project.name=test
./build/build.xml:12:<target name="sync:test">

Count Strings

If you only want to count the matching lines for each file, then you can use the following command:

$ grep -inc -e 'test' `find -type f` | grep -v :0

This will output:

./build/build.properties:1
./build/build.xml:2

Replace Strings

And finally, if you want to replace all occurrences of the search string with the replacement string:

$ sed -i 's/search/replace/' `find -type f`

Linux Commands

Learn more about these commands:

Zend_Form Performance Issues

If you are using Zend_Form and your site increases in complexity and attracts more traffic, you are most likely to run into performance problems.

Of course, bigger and more complex projects result in more load on your servers. A typical scenario might be you’ve added a few new features to a Web application and now are seeing more server load and memory usage; thus, pages seem to load slower. To solve this you can throw bigger hardware at the problem or try to find the parts of your code that are causing the slowdowns and optimize them.

In this post I’ll explain the problems I faced when using Zend_Form and how I managed to optimize it and improve the performance of my application.

Update: Matthew Weier O’Phinney wrote:

“You’ll be happy to know that I’ve already made changes in the incubator to allow lazy loading of validators, filters, and decorators. These changes will be released with version 1.6.0.”

The Problem

Zend_Form heavily depends on other Zend Framework components, such as Zend_Validate, Zend_Filter, Zend_Loader_PluginLoader and, optionally, Zend_Config.

The Zend_Form_Elements class doesn’t check for the requested method and loads all the filters and validators on each request creating an unnecessary overhead. In an ideal world, these objects should only be loaded when the elements are checked against the data provided.

1. HTTP/1.1 GET

o- (request)
-> (new form)
-> (load filters and validators)
-> (response)

2. HTTP/1.1 POST

o- (request)
-> (new form)
-> (load filters and validators)
-> (process data)
-> (response)

In the first example, when a user requests the form, Zend_Form loads all the filters and validators, but never uses them.

The Test

Zend_Form

Requests per second 1:   36.51 [#/sec]
Requests per second 2:   36.72 [#/sec]
Requests per second 3:   36.54 [#/sec]

Zend_Form + Zend_Cache

Requests per second 1:   81.54 [#/sec]
Requests per second 2:   81.38 [#/sec]
Requests per second 3:   82.01 [#/sec]

HTML Form

Requests per second 1:   94.55 [#/sec]
Requests per second 2:   94.63 [#/sec]
Requests per second 3:   94.49 [#/sec]

Benchmarks and Test Data Results

The Solution

1. Modify Zend_Form_Elements so that it checks the requested method before loading all the dependencies, otherwise Zend_Form_Elements will use Reflection to allocate unnecessary objects into memory.

2. Cache the output of the Zend_Form object using Zend_Cache.

Example

Caching Zend_Form output:

class ZendFormCachedController extends Zend_Controller_Action
{
        protected $_formId = 'form';

        public function indexAction()
        {
                $frontend = array(
                        'lifetime' => 7200,
                        'automatic_serialization' => true);

                $backend = array('cache_dir' => '/tmp/');
                $cache = Zend_Cache::factory('Core', 'File', $frontend, $backend);

                if ($this->getRequest()->isPost()) {
                        $form = $this->getForm(new Zend_Form);
                } else if (! $form = $cache->load($this->_formId)) {
                        $form = $this->getForm(new Zend_Form);
                        $cache->save($form->__toString(), $this->_formId);
                }

                $this->getHelper('layout')->setLayout('zend-form');
                $this->view->form = $form;
        }

Conclusion

Make sure you cache and optimize your code! When you add a new component to your application, make sure you have a benchmark against which you can test your code to see how the changes affect performance and efficiency.

Zend_Form Benchmarks and Test Data Results

Related Articles

PHP framework comparison benchmarks

Google gives away a free web application security scanner

Google announced the release of ratproxy, a passive web application security assessment tool that they’ve been using internally at Google. This utility, developed by their information security engineering team, is designed to transparently analyse legitimate, browser-driven interactions with a tested web property and automatically pinpoint, annotate, and prioritize potential flaws or areas of concern.

The proxy analyses problems such as cross-site script inclusion threats, insufficient cross-site request forgery defences, caching issues, cross-site scripting candidates, potentially unsafe cross-domain code inclusion schemes and information leakage scenarios, and much more.

Find out more

Get your social networking site up and running in minutes

Symfonians is an open source social networking web application written in PHP5 and based on the Symfony framework. You can see it in action here.

Features

  • Applications directory
  • People profiles directory
  • Companies directory
  • Job offers catalogue
  • People recommendations
  • Items connections
  • Simple blog management
  • Maps and geolocalization
  • Lucene searchable index
  • Microformats
  • and much more

If you’ve never used Symfony before, then this project will give you a very good understanding of how the framework works.