A colleague of mine gave a presentation today, comparing some aspects of Yii and PHP to Rails and Ruby - that and some other array-related explorations with PHP of late, got me thinking about the convention of using arrays for pretty much anything.
Somebody mentioned the issue in this thread, but I felt the topic deserves a dedicated thread.
Arrays should be used only when it makes sense - for instance, it’s great to use array for lazy initialization of behaviors, application-components, etc.
It’s not so great to use arrays everywhere else though.
For one, arrays do not provide any kind of type-checks or property checks, in IDEs, or at run-time - at least not in good time.
For another, array-manipulation is not very convenient in PHP - as my colleague pointed out, when defining additional filters in a controller sub-class, it gets really ugly and tedious:
public function filters()
{
return array_merge(parent::filters(), array(
array('another_filter'),
));
}
In addition to being inconvenient and ugly, it’s also not very flexible - as he pointed out, what if I need this or that filter added specifically before or after the filters defined by the parent class, it gets even more clunky.
Lastly, there are performance-related issues with arrays. Arrays, when passed as arguments and modified, get copied in-memory. And also, in PHP 5.4, class-properties have been optimized, so that the property-names are not copied to every instance of a class - rather, PHP now maintains a shared property-table for all instances, meaning less memory and CPU overhead for all the property-name duplicates in previous versions.
It would be much more convenient and safer to have something like this:
public function init()
{
parent::init();
$this->appendFilter(new ThisFilter('x', 'y', 'z'));
$this->prependFilter(new ThatFilter('a', 'b', 'c'));
}
For controllers, things like actions, access-rules and filters, these could be much more conveniently (and more safely) in the init() method, constructing objects and calling methods to register them.
For models, things like attribute metadata (names and labels), validations, relations, etc. could all be created directly and added via method-calls.
After all, if you load a controller or model, it’s probably because you’re about to use it, so there’s not much point in delaying or abstracting the construction of dependent objects.
Even if the delaying the initialization of validations and relations does make sense for performance reasons, it would still be safer to construct actual objects in the validations() and relations() callbacks.
On a related note, since PHP 5.3, we now have closures - which can be used for lazy instantiation, providing type-sensitivity in IDEs, and avoiding arrays. This could be useful e.g. for application components, since the configuration can now consist of actual code, not only setting properties on the constructed components, but calling methods on them, firing events, and so on.
Just some thoughts that were going through my head today.