Important: These benchmarks were run pre-1.6.0, and are largely irrelevant at this time. Zend_Form has been refactored to address all the issues mentioned in this page.
Matthew Weier O'Phinney wrote: I've already made changes in the incubator to allow lazy loading of validators, filters, and decorators; basically, the plugin objects are only instantiated when you actually need them (for instance, validators are only loaded when you either call getValidator() or isValid(); filters are only loaded when you call getFilter() or getValue(); and decorators are only rendered if you call getDecorator() or render()). These changes will be released with version 1.6.0.
Contents |
The Zend_Form component provides methods to dynamically create, validate and render HTML forms. 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.
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 --> Create form object --> Load filters and validators --> Response
2. HTTP/1.1 POST
o-- Request --> Create form object --> 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.
127.0.0.1 localhost 127.0.0.1 www.zend-test.com zend-test.com
<VirtualHost *>
ServerName www.zend-test.com
ServerAlias zend-test.com
DocumentRoot /home/zend-test/public
<Directory /home/zend-test/public>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
</Directory>
RewriteEngine on
RewriteRule !\.(js|ico|gif|jpg|png|css|html)$ /index.php
</VirtualHost>fede@dev:~$ ab -kc 10 -t 60 http://www.zend-test.com/
10 connections opened, using Keep-Alive, requesting http://www.zend-test.com/ for 60 seconds through those connections.
application/
|-- bootstrap.php
|-- controllers
| |-- ErrorController.php
| |-- HtmlFormController.php
| |-- ZendFormCachedController.php
| `-- ZendFormController.php
|-- layouts
| `-- zend-form.phtml
|-- models
`-- views
`-- scripts
|-- error
| |-- not-found.phtml
| |-- server-error.phtml
| `-- setup-error.phtml
`-- index
`-- index.phtml
library/
`-- Zend
public/
`-- index.phpServer Hostname: www.zend-test.com Document Path: /zend-form Requests per second 1: 36.51 [#/sec] Requests per second 2: 36.72 [#/sec] Requests per second 3: 36.54 [#/sec]
Server Hostname: www.zend-test.com Document Path: /zend-form-cached Requests per second 1: 81.54 [#/sec] Requests per second 2: 81.38 [#/sec] Requests per second 3: 82.01 [#/sec]
Server Hostname: www.zend-test.com Document Path: /html-form Requests per second 1: 94.55 [#/sec] Requests per second 2: 94.63 [#/sec] Requests per second 3: 94.49 [#/sec]
class ZendFormController extends Zend_Controller_Action { public function indexAction() { $this->getHelper('layout')->setLayout('zend-form'); $this->view->form = $this->getForm(new Zend_Form); } public function getForm(Zend_Form $form) { $form->setName('test_form'); $form->setAction('/zend-form/edit'); $form->setAttrib('action','edit'); $form->setMethod('post'); $form->clearDecorators(); $form->addDecorator('FormElements') ->addDecorator('HtmlTag', array('tag' => '<ul>')) ->addDecorator('Form'); $form->setElementDecorators( array( array('ViewHelper'), array('Errors'), array('Description'), array('Label', array('separator'=> '')), array('HtmlTag', array('tag' => 'li', 'class' => 'element-group')), ) ); $hiddenField = new Zend_Form_Element_Hidden('action'); $form->addElement($hiddenField); $field1 = new Zend_Form_Element_Select('field1'); $field1->setLabel('Field 1') ->setMultiOptions(array('a'=>'a', 'b'=>'b')) ->setRequired(true) ->addValidator('NotEmpty', true); $form->addElement($field1); $field2 = new Zend_Form_Element_Text('field2'); $field2->setLabel('Field 2') ->setRequired(true) ->addValidator('alnum') ->addValidator('NotEmpty') ->addValidator('regex', false, array('/^[a-z]/')) ->addFilter('StringToLower'); $form->addElement($field2); $field3 = new Zend_Form_Element_Textarea('field3'); $field3->setLabel('Field 3') ->setRequired(true) ->addValidator('NotEmpty') ->addFilter('StripTags'); $form->addElement($field3); $field4 = new Zend_Form_Element_Text('field4'); $field4->setLabel('Field 4') ->setRequired(true) ->addValidator('stringLength', false, array(20)) ->addValidator('EmailAddress') ->addFilter('StringTrim'); $form->addElement($field4); $field5 = new Zend_Form_Element_Text('field5'); $field5->setLabel('Field 5') ->setRequired(true) ->addValidator('stringLength', false, array(20)) ->addValidator('NotEmpty'); $form->addElement($field5); $field6 = new Zend_Form_Element_Radio('field6'); $field6->setLabel('Field 6') ->setRequired(true); $form->addElement($field6); $submit = new Zend_Form_Element_Submit('submit'); $submit->setDecorators( array( array('ViewHelper'), array('Description'), array('HtmlTag', array('tag' => 'li', 'class' => 'submit-group')), ) ); $form->addElement($submit); $reset = new Zend_Form_Element_Reset('reset'); $reset->setDecorators( array( array('ViewHelper'), array('Description'), array('HtmlTag', array('tag' => 'li', 'class' => 'submit-group')), ) ); $form->addElement($reset); return $form->render(); } }
class ZendFormCachedController extends Zend_Controller_Action { protected $_formId = 'form'; public function indexAction() { $frontendOptions = array( 'lifetime' => 7200, 'automatic_serialization' => true); $backendOptions = array('cache_dir' => '/tmp/'); $cache = Zend_Cache::factory('Core', 'File', $frontendOptions, $backendOptions); 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, $this->_formId); } $this->getHelper('layout')->setLayout('zend-form'); $this->view->form = $form; } public function getForm(Zend_Form $form) { ... } }
class HtmlFormController extends Zend_Controller_Action { public function indexAction() { $this->getHelper('layout')->setLayout('html-form'); } }
define('APPLICATION_DIRECTORY', dirname(__FILE__)); set_include_path(dirname(APPLICATION_DIRECTORY) . '/library'); require_once 'Zend/Loader.php'; Zend_Loader::registerAutoload(); // set Model path in include path set_include_path(get_include_path() . PATH_SEPARATOR . APPLICATION_DIRECTORY . '/models'); // bootstrap layouts Zend_Layout::startMvc(array( 'layoutPath' => APPLICATION_DIRECTORY . '/layouts', 'layout' => 'main' )); Zend_Controller_Front::run(APPLICATION_DIRECTORY . '/controllers');