views:

40

answers:

1

I'm learning Zend Framework at the moment and came across the following syntax.

class Zend_Controller_Action_Helper_Redirector extends Zend_Controller_Action_Helper_Abstract
{
    /**
     * Perform a redirect to an action/controller/module with params
     *
     * @param  string $action
     * @param  string $controller
     * @param  string $module
     * @param  array  $params
     * @return void
     */
    public function gotoSimple($action, $controller = null, $module = null, array $params = array())
    {
        $this->setGotoSimple($action, $controller, $module, $params);

        if ($this->getExit()) {
            $this->redirectAndExit();
        }
    }

    /**
     * direct(): Perform helper when called as
     * $this->_helper->redirector($action, $controller, $module, $params)
     *
     * @param  string $action
     * @param  string $controller
     * @param  string $module
     * @param  array  $params
     * @return void
     */
    public function direct($action, $controller = null, $module = null, array $params = array())
    {
        $this->gotoSimple($action, $controller, $module, $params);
    }
}

In Zend Framework the direct() method in this class can be called using the following syntax:

$this->_helper->redirector('index','index');

Where redirector is an object(!) in the _helper object, which is inside the controller object, in which we call the method. The syntactic sugar here is that you can just pass parameters to the object instead of to the method, which we would write like so:

$this->_helper->redirector->gotoSimple('index','index');

..which is all fine and dandy ofcourse.

Here's my question: is this direct() method standard in OO PHP? Or is this functionality built into Zend Framework? I can't find any documentation on this.

Thanks!

+7  A: 

It is functionality build into Zend Framework.

The $_helpers property in the Controller instance holds an Action_HelperBroker instance. This instance implements PHP's magic __call method. When you call a method that does not exist on that instance, it will try to use the method name to fetch a helper of the same name and call direct() on it (if possible). See code below.

From Zend_Controller_Action

/**
 * Helper Broker to assist in routing help requests to the proper object
 *
 * @var Zend_Controller_Action_HelperBroker
 */
protected $_helper = null;

From Zend_Controller_Action_HelperBroker

/**
 * Method overloading
 *
 * @param  string $method
 * @param  array $args
 * @return mixed
 * @throws Zend_Controller_Action_Exception if helper does not have a direct() method
 */
public function __call($method, $args)
{
    $helper = $this->getHelper($method);
    if (!method_exists($helper, 'direct')) {
        require_once 'Zend/Controller/Action/Exception.php';
        throw new Zend_Controller_Action_Exception('Helper "' . $method . '" does not support overloading via direct()');
    }
    return call_user_func_array(array($helper, 'direct'), $args);
}

The Helper Broker also implement the magic __get method, so when you try to access a property that does not exist, the broker will use the property name as an argument to getHelper()

/**
 * Retrieve helper by name as object property
 *
 * @param  string $name
 * @return Zend_Controller_Action_Helper_Abstract
 */
public function __get($name)
{
    return $this->getHelper($name);
}

Please be aware that magic methods are not meant as a replacement to a proper API. While you can use them as shown above, calling the more verbose

$this->_helper->getHelper('redirector')->gotoSimple('index','index');

is often the much faster alternative.

Gordon
Additionally you can read about helpers (and `direct` method) here: http://devzone.zend.com/article/3350
c64ification
That is some nice code there. Thanks for pointing it out!
Niels Bom
After your edit: you talk about the longer syntax being the faster alternative, are we talking a lot faster or is this fairly negligible? OK this depends of course, but is it like the comparision of parsing a double quoted string with variables or concatenating single quoted strings and variables?
Niels Bom
@Niels It is a µ-optimization and wont matter if you only have a few calls like this. But if you have a lot of these calls it can have an impact. A similar technique is used for ViewHelpers, e.g. calling `$this->helperName()` in a View will use magic methods to find and call the helper. On my current project we have pages that do hundreds of calls to ViewHelpers when rendering the page. There it made a difference whether I called the helper directly or through the magic method. Also see http://stackoverflow.com/questions/3330852/get-set-call-performance-questions-with-php
Gordon
Solid explanation
David Caunt