Create meaningful class attributes, not ambiguous arrays, in PHP

December 29th, 2007 by rvdavid Leave a reply »

Happy holidays guys, it’s been a while since the last update, but I’ve been busy tweaking our framework at devproducts and wrappin’ presents that I’ve not had the time to actually make any valid posts aside from the odd I shopped here and there post, so I thought it would have been best to keep quiet until I had something meaningful to say.

A couple of years ago, when I had come across some code I had coded when I had first started learning OOP. I came across an object coined “DataSpace” from frameworks like WACT which used this uber-cool pattern.

Going through some of my old code, I’ve noticed some serious flaws. This “DataSpace” been applied wayyyy too liberally throughout almost all my applications.

At one point, my programming technique had somehow strayed from the path and I actually found myself abstracting actual properties or attributes of a class into an array which served as a generic container for properties and attributes.While this seemed neat at the time, doing things this way made the properties or attributes of the class very ambiguous. This also took away the structural description that an attribute or property would provide.

Here are a couple of examples.A person class coded using a properties array/key map as it’s sole property – very clever, it looks a little cleaner than the next example and also, we do not have to worry about adding extra attributes if we need them down the track but important parts are sacrificed. For example, say that we had it down that the Person class should have name, height, age and gender as its attributes. The convenience of this class is that the properties array is dynamic, all we need to do to add another “property” is to just add another $this->set(‘weight’,$weight) to the mix.


class Person
{
    protected $_attributes = array(); // name, height, age, gender
    public function __construct($name,$height,$age,$gender)
    {
        $this->set('name', $name);
        $this->set('height', $height);
        $this->set('age', $age);
        $this->set('gender', $gender);
    }

    public function get()
    {

    }

    public function set($prop, $value)
    {

    }
}

?>

But there are some very important things that are sacrificed with this method. By having a dynamic properties array, there is no way we can express what the class structure will look like aside from the constructor’s parameters, ignoring the fact that this is a “workaround” for the limitation we injected by not havinga concrete set of attributes for our class, this method of describing structure through constructor parameters may become problematic – what if we have more than 4 attributes we need to set?

With a dynamic attributes array being used in place of the traditional type we’re going to run into so many dead ends that we’ll find ourselves giving up and realising that we cannot express the structure of the class with code alone, so we will have to rely on examples and documentation. But this too has it’s downfalls and chores, every time you change the class and add an attribute, you will need to update the documentation and/or example. Which defeats the convenience purposes we implemented this clever little class in the first place!

Let’s go crawling back to the old school way of doing things – using attributes to describe the structure of the class.

The preferred way of writing a class, the attributes make the structure of the class obvious - by looking at this example you will know at first glance that the Person class has name, height , age and gender as its attributes in contrast to the previous example where one may have to rely on a constructors parameter, documentation and/or code samples.

< ?php
class Person
{
    // protected $_attributes = array();
    protected $_name;
    protected $_height;
    protected $_age;
    protected $_gender;

    public function __construct($name,$height,$age,$gender)
    {
        $this->_name = $name;
        $this->_height = $height;
        $this->_age = $age;
        $this->_gender = $gender;
    }

    // getters

    // settters
}
?>

Of course every time you add or remove an attribute you will have to add or remove getter and setter methods, but this is the only thing you will have to worry about. The class describes itself, each of the methods associated with the attribute or property makes sense.

To conclude, there’s a lesson in all this and that’s to keep your class attributes _AS_ attributes as opposed to a dynamic array of attributes. An attribute plays a major role in describing the structure of the class and should not be made dynamic – there’s more work in maintaining dynamic attributes, not to mention it opens the door to an “anything fits” scenario where our Person class can have attributes like “wheels” or “fences” and would still seem semantic to have them as the dynamic getter and setter methods allows this of course this could be prevented _with_ documentation but you shouldn’t have to.

if you enjoyed this post, make sure you subscribe to my RSS feed!
You can also follow me on Twitter here.

No related posts.

Advertisement

4 comments

  1. Gary says:

    Apologies for dragging up a very old post, but I’m just trying to get into Zend Framework, and the dynamic array way of doing things is my latest “Oh, that’s a good idea” things to note as a good practice.

    If the attributes (values of the array) are descriptive enough (and yes, I could well imagine long unwieldy array keys) so that documentation is not needed, would this concept still be valid?

    Furthermore, as this post was over two years ago, have your impressions of it changed at all?

    • rvdavid says:

      Hi Gary,

      No problems. To answer your question, I’d still say that I would still lean toward my recommendation but do so with the addition of a Unified Constructor. The point I was trying to make here is to avoid relying on Arrays to serve as a means to represent the structure of the class.

      The post is a little old and was midway to how I now look at things. The example on this post uses several parameters in the constructor, but now I tend to use arrays to setup attributes (ala Unified Constructor). See more about Unified Constructor at http://framework.zend.com/wiki/display/ZFDEV2/Zend+Framework+2.0+Roadmap

      My preference for communicating class attributes still does not change, but I now see the convenience in providing the ability to set up a class by using one array. Anything that draws away from common expectations of how a class is written will lead to confusion down the track, even if it was your own code you’re looking at (from my experience anyway).

      If I had to rewrite the Person Class, I’d do it in the following manner:

      < ?php
      class Person
      {
      protected $_name;
      protected $_height;
      protected $_age;
      protected $_gender;

      public function __construct($options=array())
      {
      $this->setOptions($options);
      }

      public function setOptions($options)
      {
      foreach ($options as $key => $value) {
      $method = 'set' . $key;
      if (method_exists($this, $method)) {
      $object->$method($value);
      }
      }
      }

      public function setName($name) {$this->_name=$name;}
      public function setHeight($height) {$this->_height=$height;}
      public function setAge($age) {$this->_age=$age;}
      public function setGender($gender) {$this->_gender=$gender;}
      }

      // usage

      $person = new Person(array('age'=>'25', 'name'=>'John Doe', 'height'=>177,'gender'=>'maile');

      ?>

      Not tested – but you get the gyst. I still have my attributes set up so that when I look at the class at first glance, I know that a person class as far as my program is concerned, has the following attributes: name, height, age and gender. There is no clearer way to communicate this. Not even with a “verbosely” named array.

      Hope this helps.

      • Gary says:

        Hey, thanks for the detailed reply.

        This is the first time I’ve come across the term Unified Constructor, so I’ll have a read of the article you sent (I read the roadmap page yesterday, but totally skipped over that part).

        Your code above seems to fall somewhere between writing it all out in full, and what I’ve seen in a couple of Matthew W O’P's recentish slideshows.

        It also looks like it might encompass something I was trying to do – use an equivalent of the __set() magic methods for the majority of accessible property setting, but allow for individual setX() methods if they existed.

        I’ve still got a long way to go with it all (currently getting to grips with the concept of Service Layers and how they and the models mappers all fit together), and deciphering everyone’s opinions from any sort of accepted best practices is taking time, but having blog articles available is muchly appreciated, so thank you :-)

        • rvdavid says:

          lol you’re going to have a lot of fun. IMHO Service Layers are the way to go. I’m currently working on an application and it has aided me greatly in semantically separating concerns.

          Which is IMHO nowadays is slowly starting to look like another fancy way of saying “thin controllers”. (j/k)

Leave a Reply

Notify me of followup comments via e-mail. You can also subscribe without commenting.