PhpRiot
Become Zend Certified

Prepare for the ZCE exam using our quizzes (web or iPad/iPhone). More info...


When you're ready get 7.5% off your exam voucher using voucher CJQNOV23 at the Zend Store

How can I speed up calls to the action() view helper?

Version 1.5.0 introduced the action() view helper, which allows you to dispatch an MVC action and capture its rendered content. This provides an important step towards the DRY principle, and promotes code reuse. However, as those who profile their applications will quickly realize, it, too, is an expensive operation. Internally, the action() view helper needs to clone new request and response objects, invoke the dispatcher, invoke the requested controller and action, etc.

How can you speed it up?

Use the ActionStack when possible

Introduced at the same time as the action() view helper, the ActionStack consists of an action helper and a front controller plugin. Together, they allow you to push additional actions to invoke during the dispatch cycle onto a stack. If you are calling action() from your layout view scripts, you may want to instead use the ActionStack, and render your views to discrete response segments. As an example, you could write a dispatchLoopStartup() plugin like the following to add a login form box to each page:

class LoginPlugin extends Zend_Controller_Plugin_Abstract
{
    protected $_stack;

    public function dispatchLoopStartup(
        Zend_Controller_Request_Abstract $request
    ) {
        $stack = $this->getStack();
        $loginRequest = new Zend_Controller_Request_Simple();
        $loginRequest->setControllerName('user')
                     ->setActionName('index')
                     ->setParam('responseSegment', 'login');
        $stack->pushStack($loginRequest);
    }

    public function getStack()
    {
        if (null === $this->_stack) {
            $front = Zend_Controller_Front::getInstance();
            if (!$front->hasPlugin('Zend_Controller_Plugin_ActionStack')) {
                $stack = new Zend_Controller_Plugin_ActionStack();
                $front->registerPlugin($stack);
            } else {
                $stack = $front->getPlugin('ActionStack')
            }
            $this->_stack = $stack;
        }
        return $this->_stack;
    }
}

The UserController::indexAction() method might then use the $responseSegment parameter to indicate which response segment to render to. In the layout script, you would then simply render that response segment:


<?php $this->layout()->login ?>

While the ActionStack still requires a dispatch cycle, this is still cheaper than the action() view helper as it does not need to clone objects and reset internal state. Additionally, it ensures that all pre and post dispatch plugins are invoked, which may be of particular concern if you are using front controller plugins for handling ACL's to particular actions.

Favor helpers that query the model over action()

In most cases, using action() is simply overkill. If you have most business logic nested in your models and are simply querying the model and passing the results to a view script, it will typically be faster and cleaner to simply write a view helper that pulls the model, queries it, and does something with that information.

As an example, consider the following controller action and view script:

class BugController extends Zend_Controller_Action
{
    public function listAction()
    {
        $model = new Bug();
        $this->view->bugs = $model->fetchActive();
    }
}

// bug/list.phtml:
echo "<ul>\n";
foreach ($this->bugs as $bug) {
    printf("<li><b>%s</b>: %s</li>\n",
        $this->escape($bug->id),
        $this->escape($bug->summary)
    );
}
echo "</ul>\n";

Using action(), you would then invoke it with the following:


<?php $this->action('list''bug'?>

This could be refactored to a view helper that looks like the following:

class My_View_Helper_BugList extends Zend_View_Helper_Abstract
{
    public function bugList()
    {
        $model = new Bug();
        $html  = "<ul>\n";
        foreach ($model->fetchActive() as $bug) {
            $html .= sprintf(
                "<li><b>%s</b>: %s</li>\n",
                $this->view->escape($bug->id),
                $this->view->escape($bug->summary)
            );
        }
        $html .= "</ul>\n";
        return $html;
    }
}

You would then invoke the helper as follows:


<?php $this->bugList() ?>

This has two benefits: it no longer incurs the overhead of the action() view helper, and also presents a more semantically understandable API.

Zend Framework