Friday, September 18, 2009

Zend Framework Api: what $options is?

I wanted to share an insight that repetitevely using and studying the Zend Framework API has given me. I know finding a lack in documentation can be annoying but ZF is usually very coherent in its API and I find out it is predictable also in this case, which is a good trait for a very large set of classes such as the one from Zend.

The tipical constructor of a Zend Framework class (or factory method) has a signature such as:
Zend_Form::__construct([mixed $options = null]);
and this always left me wondering what would $options contain, since I cannot found a documentation for this constructor. I depended on finding examples in the reference manual for what I want to do with my objects.
What I have learned is a convention widely used in Zend Framework main components and in the incubator: the options are passed to the setters after the mandatory construction process have taken place. This means that if we build a submit button in this way:
$button = new Zend_Form_Element_Submit('submit', array('ignore' => true, 'value' => 'Click me'));
the result is equivalent to:
$button = new Zend_Form_Element_Submit('submit');
$button->setIgnore();
$button->setValue('Click me');
So you can simply refer to the documentation of the particular setter you want to call in the constructor and provide a key in the array with the initial lowercase (to respect the Pear/Zend coding standard): setElementsBelongTo() will require a elementsBelongTo key.

It would be interesting to know if there is an official guideline to provide constructors like the ones in Zend_Form component or if do some classes follow a different convention: feel free to share what you know in the comments.

7 comments:

mweierophinney said...

Yes -- the "unified constructor" that accepts an array (or Zend_Config object) of options that relate to the defined setters is a current guideline. However, since many components pre-date the practice, we're having to slowly refactor constructors throughout the framework to follow the paradigm.

We decided on this for several reasons. One, as you note, is predictability; if all constructors act in the same way, it's really easy to know what you should pass. Another is to prepare the framework for dependency injection; having a common constructor paradigm such as this makes it easy to use DI containers with the components.

Glad you figured out the feature, and found it useful!

Giorgio said...

Thank you for the feedback Matthew. I'm looking forward to see DI techniques in the Zend Framework.

Olagato said...

Hi, Giorgio
Here is an example of DI techniques in the Zend Framework:

http://www.whitewashing.de/blog/articles/117

Giorgio said...

Olagato,
thanks for the link. I recently worked with Benjamin on Zend_Entity but I'm currently blocked by the CLA.
However, I was thinking of DI in the core components of zf, to increase their decoupling.

Norbert said...

Anyone knows how is this implemented?
Is it:

foreach ($options as $k => $v) {
$method = 'set' . ucfirst($k);
if (method_exists($this, $method)) {
$this->$method($v);
}
}

Giorgio said...

Norbert,
you can find an example in the Zend_Form class:
$method = 'set' . $normalized;
if (method_exists($this, $method)) {
$this->$method($value);
} else {
$this->setAttrib($key, $value);
}

Ulric Stein said...

I know finding a lack in qualifications can be annoying but ZF is usually very constant in its API and I find out out it is predicted also in this scenario, which is a fantastic function for a very large set of classes such as the one from Zend.

ShareThis