Skip to content

Instantly share code, notes, and snippets.

@mindplay-dk
Last active February 16, 2016 07:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mindplay-dk/635423d1078f09a41fbe to your computer and use it in GitHub Desktop.
Save mindplay-dk/635423d1078f09a41fbe to your computer and use it in GitHub Desktop.
Documenting accessors

How do you document model attributes implemented using synchronous accessor methods?

Example - bare model, no documentation:

class Contact
{
    protected $phone;
    
    public function getPhone() {
        return $this->phone;
    }

    public function setPhone($phone) {
        $this->phone = $phone;
    }
}

Let's say I wanted to document the phone-attribute as being the Contact's phone number, with no spaces, dashes or special characters.

You could duplicate the documentation two, or even three times:

class Contact
{
    /**
     * @var string phone number, with no spaces, dashes or special characters
     */
    protected $phone;
    
    /**
     * @return string phone number, with no spaces, dashes or special characters
     */
    public function getPhone() {
        return $this->phone;
    }
    
    /**
     * @param string $phone phone number, with no spaces, dashes or special characters
     */
    public function setPhone($phone) {
        $this->phone = $phone;
    }
}

This is obviously a horrible option - you're now maintaining documentation in triplicate, or at least in duplicate if you leave out the commen on $phone, which at the very least should state the type for proper IDE support.

Either way, pretty soon, someone's going to forget to copy/paste that comment when making changes, and then we won't know which one is correct or up to date.

Duplicating the type-annotation times 3 is also pretty lame.

If we had to pick one of those three and skip documentation for the others, that gives us three options: document just the backing field, in which case consumers of the public API methods are working blind-fold; document just the getter or the setter, in which case you'll have to decide which is more important, reading or writing - and someone writing consumer code better remember to check either one or the other accessor.

All of those options are crap.

I personally tend to prefer keeping accessor internal, and mapping to virtual properties - for example:

trait Accessors // (simplified...)
{
    public function __get($name) {
        return $this->{"get_{$name}"}();
    }
    
    public function __set($name, $value) {
        $this->{"set_{$name}"}($value);
    }
}

/**
 * @property string $phone phone number, with no spaces, dashes or special characters
 */
class Contact
{
    use Accessors;

    protected $_phone;
    
    protected function get_phone() {
        return $this->_phone;
    }

    protected function set_phone($phone) {
        $this->_phone = $phone;
    }
}

At least, this way, public documentation for the attribute goes in one place, instead of two.

Also, this refactors nicely between real and virtual properties with no breaking changes.

It's still a trade-off though, as the backing field remains undocumented, but at least this affects only that class internally now, and the documentation at least is at-hand, in the file you're editing, when you're missing it, and it's easier to locate near the top of the file.

Either way, my coworkers don't accept this, because, ew, magic - and also this has an ugly performance impact.

Other languages have accessors, probably for all of those reasons, but that's too fancy for PHP.

So instead of documentation, we get junk comments auto-generated by IDEs. Brilliant comments like "sets the Phone" for methods like setPhone() - Hello, Captain Obvious. (if your code standard says methods must be documented, that's a nice, quick way around actually documenting anything...)

How do you deal with this?

@MattiJarvinen
Copy link

I'd use http://www.phpdoc.org/docs/latest/references/phpdoc/tags/see.html

Syntax might be a bit off since not at my IDE now.

class Contact
{
    /** @var string $_phone phone number, with no spaces, dashes or special characters */
    protected $_phone;

   /**
     * @param string $phone 
     * @see Contact::$_phone 
     */
   public function setPhone($phone)
   {...

@MattiJarvinen
Copy link

And while at it in phpdoc @property for the class should be enough for magic properties. http://www.phpdoc.org/docs/latest/references/phpdoc/tags/property.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment