The use of setters/getters on internal methods

Hey fellow Sitepointers,

I’m just wondering what your opinions are on the use of setters and getters on internal methods, do you see it as best practise to use them or to refer to the property directly? (see below)

I know it’s a small thing, but as I’m writing my classes it’s often small things like this which play on my mind and make me wonder what the best practice is.

page.php


<?php

$page = new Page($_GET['pid']);

echo "<h1>" . $page->getTitle() . "</h1>"; 

echo $page->getBodyText();

?>


page.class.php



<?php

class Page {

protected $_pageId;

public function __construct($pid) {

$this->_pageId = $pid;

$this->getPage();

}

public function getPageId() {
return $this->_pageId;
}

private function getPage() {

/* This method of printing out the page id internally */
$sql = "SELECT title, bodytext FROM page WHERE pid = " . $this->getPageId() . " LIMIT 1";

/* or refer to the property directly, like this */
$sql2 = "SELECT title, bodytext FROM page WHERE pid = " . $this->_pageId . " LIMIT 1";
}

}

?>

To me, personally, it makes more sense to use the getPageId() method for a few reasons, the main one being it makes it easier to change the $this->_pageId variable without having to change it in multiple places…

I personally use the actual instance variable inside the class and not the getter. This is not a big deal, but I don’t see a benefit to add one more method call to the program.
Sure it’s super fast to call such method but if you have hundreds of places where you call unnecessary getters then it all adds up.

Setters and Getters are useful when dealing with a classic OO language… as they allow you the ability to override the default input or output with additional information, formatting, or restrictions… Even in a classic OO model, if you’re just getting and setting directly to the private parameter, you’re adding a lot of unnecessary overhead for the sake of consistency… it can be a mess.

With PHP, we are afforded the ability to “wrap” sets and gets without adding setter and getter methods, though, using magic methods (__set and __get).

The key to using these tools to simplify your life is to think outside the box, and not think of properties in the traditional sense.

An example of an alternative model you can use with PHP is:


class DAOAbstract {
    private $params = array();
    private $values = array();
    public function __construct(array $params, array $values=null) {
        $this->params = $params;
        if (!is_null($values)) $this->values = $values;
    }
    public function __get($key) {
        if (!array_key_exists($key, $this->params)) throw new Exception("Invalid property specified.");
        if (array_key_exists($key, $this->values)) {
            return $this->values[$key];
        } else {
            return null;
        }
    }
    public function __set($key, $value) {
        if (!array_key_exists($key, $this->params)) throw new Exception("Invalid property specified.");
        switch ($this->params[$key])) {
            case "int":
                $value = (int) $value;
                break;
            case "varchar":
                $value = (string) $value;
                $value = mysql_real_escape_string($value);
                break;
        }
        $this->values[$key] = $value;
    }
}

class PageDAO extends DAOAbstract {
    public function __construct(array $values = null) {
        $params = array("id" => "int", "name" => "varchar", "title" => "varchar", "body" => "varchar")
        parent::__construct($params, $values);
    }
}


This way, you can having an abstract DAO base, which you extend only to specify your params… your actual DAO classes are extremely simple!

I’ve taken this concept to the limit to create my DAO Abstract (which I call “Archetype”)… as part of my framework.

File Source for Archetype.php

It depends. Some folks think that setters/getters are evil - and that you should just be able to acquire the properties directly. Personally, I think it depends on the requirement. For example, setters and getters allow you to conduct checks on the incoming data prior to setting, or to update other aspects of the class. If you do not need to perform these sorts of checks, then why bother?

I use getters and setters 99% of the time because a) when a class property is supposed to be a certain type of object I can employ type hinting, and b) it avoids bugs that creep up when a property name is misspelled. Both of these things save me hours of debugging time.

I always use getters and setters.

@AnthonySterling

If you provide direct access to an attribute with getters and setters - isn’t it just overkill?

I use getters and setters if:

1: I need to trigger internal behaviour when accessing the attributes

2: I wish to store the value in a custom internal array/class

3: I want to prohibit access in one direction (i.e get OR set)

Maybe.

However, I’ve never run into any issues when I have used them, yet ran into a fair few where I haven’t.

It’s much easier to bolt on points 1, 2 and 3 (and possibly 4 and 5) without disturbing any of the other code-base when you already have getters/setters already defined and in use.

It’s a trivial upfront cost in my opinion.

Hi…

I don’t usually refer to properties directly, although I may fake that syntax with __get() and __set() trickery for client code brevity.

I don’t write many accessors either. If you find that another class want to peek inside yours for a calculation, it’s a pretty good guess you need to bring both data and code together into the same class. Either move the calculation or move the underlying variable? These questions often point to higher order design issues.

You original example maps a class to a page right down to HTML tags. There is nothing special about a title, it’s just a text property. How about a template class instead…


$template = new Template('path/to/source.html');
$template->substitute(array('title' => 'Password reminder', 'username' => $username));
$template->confirm = new Form(new PasswordField('p'), 'Go');
print $template->render();

This will work for more than just HTML pages and is easy to extend. It’s also fast if the underlying templates are PHP code.

yours, Marcus

This discussion reminds me of one on the dev list - a proposal to revise getters and setters to a C# style in PHP 5.4. The link below will become useable once the php wiki is back up from the hack attack last month.

[windows|wiki].php.net is down for maintenance