27

Okay, this is really bugging me and I'm starting to think it all comes down to personal choice rather than a particular way of being more efficient or writing better code: Should I or should I not use getter/setter methods within a PHP project? The answers so far that I've read are rather conflicting and not entirely suited towards PHP, which is not a compiled language. For example, take this question on Stack Overflow ("Why use getters and setters?"). There's a number of good reasons presented as to why I should use them within my code, yet all the child comments mention how Accessors are evil and should be avoided, interspersed between a few more disturbing comments which mention that they should be avoided entirely because it "mucks up your code".

All I'm getting is conflicting answers, none of which are relevant to a interpreted PHP environment. Can someone shine some light on why/why not they should be used within PHP, and their rationale behind that decision? Does it really matter if we can simply define a property as private or protected and, anyway:

The encapsulation getters and setters offer are laughably thin

... quoted from "sbi" (Why use getters and setters?)

Personally, I still don't see how:

Class Foo {
    public $bar;

    function setBarType($val) {
       $this->bar = $val;
    }
}

$fee = new Foo();
$fee->setBarType(42);

is superior to this:

Class Foo {
    public $bar;
}

$fee = new Foo();
$fee->bar = 42;
Community
  • 1
  • 1
marked-down
  • 9,958
  • 22
  • 87
  • 150
  • 4
    You have possibility to check `$val` before assigning and if something goes wrong throw exception, trigger user error or just return setter (first one is advisable) in your first example (actually, that's the point of encapsulation). – Leri Aug 21 '13 at 08:02
  • @Leri, that actually makes a lot of sense. But does that mean I have to have get/set methods for each property in a class, what happens if I have 50 different properties - a getter/setter for each? – marked-down Aug 21 '13 at 08:08
  • 3
    Class having 50 different properties most likely violates SRP. Anyway, it's developers choice. For example, I never use getters/setters for DTOs while I use them for DomainObjects because I use DTOs just for mapping data (mostly with reflection), while in DomainObjects I need to ensure I have _correct_ data. – Leri Aug 21 '13 at 08:13
  • Read "object oriented software construction" book – Shaheer Aug 21 '13 at 08:57

7 Answers7

22

The blog post you linked to starts with a crucial sentence (emphasis added) :

Every getter and setter in your code represents a failure to encapsulate and creates unnecessary coupling.

Encapsulation is the most important idea of Object Oriented Programming. It essentially boils down to hiding complexity by wrapping it neatly inside classes. In an ideal world, when you use a class, you shouldn't have to know anything whatsoever about its inner workings or its state. Some people (like this blog author) will argue that having getters and setters is already way too much information about the insides of the class. In their view, a class should only have methods that enable us to tell an object to do something, never mind how it does it or what state it is in. Using a setter is not "telling the object to do something", it is mucking with the object's state from outside.

Instead of doing this :

$a = myObject();

// Querying object state, making a decision outside the object, and changing its state
if ($a->getWarbleFizz() < 42) {
    $a->setYourWarbleFizzTo(42);
}

// Gee, I hope I made the right decision...
$a->nowDoSomethingUseful();

You should be writing code like this :

$a = myObject(42);
$a->doStuff();

Or this :

$a = myObject();
$a->doStuff(42);

Related reading : Tell, don't ask.

Miklos Aubert
  • 4,405
  • 2
  • 24
  • 33
  • Link is broken now: https://web.archive.org/web/20200426154726/https://pragprog.com/articles/tell-dont-ask – Matthew Oct 13 '20 at 06:11
15

Because if the implementation of how the value is set changes (to a db), you don't have to change the callers. Another example is that you may need to do some checking on the value before setting it.

Having a method lets you intercept the setting/getting of that variable, doing it when it doesn't seem like you need it makes your code more change friendly.

Property getters

Languages like C# and recent versions of JavaScript allow you to intercept property reading and writing, so you can just use properties in languages that support it.

Object watchers

Some languages allow you to intercept the reading/setting of all JavaScript's Object.watch, or inaccessible properties with PHP's __get. This allows you to implements getters and setters but you get a performance hit because of the overhead they create for every property access. This answer talks about other problems with getters and setters. Best practice: PHP Magic Methods __set and __get

Getters and Setters are OK, but...

Just making boilerplate getters and setters is better, but is almost as bad as public properties. If anybody can change your object's state (specially with multiple properties), it won't be well encapsulated. http://cspray.github.io/2012/05/13/stop-calling-them-getters-setters.html

Community
  • 1
  • 1
Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
  • Okay, but say I fetch alot of information from a database, maybe 10 different variables of information, do I have to have getter/setter methods for *each* variable, or just the array they were delivered to from the db? Because if it's the former, I see code becoming very complicated very fast. – marked-down Aug 21 '13 at 08:06
  • That's up to you, it's beyond the scope of this question and I can't really comment on a hypothetical. Also stackoverflow.com is not the place for those questions. programmers exchange is for more open ended questions like that – Ruan Mendes Aug 21 '13 at 08:13
  • You can intercept property reading and writing in PHP too: http://www.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.members – Marek Aug 21 '13 at 08:13
  • @Marek It's not the same thing, it won't get called for properties that exist. It's also really slow and should be used sparingly, since the page you linked explained a number of bugs. This is more like `Object.watch` in JS, not like getters and setters – Ruan Mendes Aug 21 '13 at 08:20
  • @Juan It's called on inaccessible properties, and having getters and setters assumes the properties are declared private/protected. – Marek Aug 21 '13 at 09:30
  • @Marek That's true, added info about using magic properties for implementing getters and setters. – Ruan Mendes Aug 21 '13 at 16:57
8

A great profit of using a getter and setter is, whenever you need to make changes you only have to modify the getter and setter.

I'll try to explain with an example:

protected $date;
public function getDate(){
    return $this->date;
}
public function setDate($date){
    $this->date = $date;
}

Imagine there is a reason the date should always be incremented with one day. You will have to search in your entire project where you accessed your class member.

But by using getters and setters you could change the code to:

protected $date;
public function getDate(){
    return $this->date;
}
public function setDate($date){
    $date = new DateTime($date);
    $date->modify('+1 day');
    $this->date = $date;
}
NLZ
  • 935
  • 6
  • 12
5

One OOP principe is encapsulation. A class is responsible to all variables that are contained inside this class.

By setting a public variable, you are breaking that principe.

By creating an accessor (setter), you're indirectly breaking that principe by giving a chance for that value to be changed outside of the class.

The advantage of a getter is that the calling method don't need to care about how the data is retrieved. It only know that it will get the expected data and that's all. Here the encapsulation principe is respected.

The advantage of a setter is that the class have the chance to check the new value before applying it. In a perfect world, there is no need for accessors because a class can fully manage all his variables. In the real world, sometimes you need to set a value or get it from the outside.

The best way to approach the perfect world is to limit accesors only to the very few variables that have to be modified. And check setted values if possible.

About your example, the second solution is better because you save one level in the php stack. Your accessor is useless because you variable is public anyway (so, no encapsulation) and don't perform any additionnal check. But when possible, you SHOULD use accessor to check the data. If the data isn't needed anywhere else in your application, then, don't do any accessor.

Atrakeur
  • 4,126
  • 3
  • 17
  • 22
  • `is to limit accesors only to the very few variables that have to be modified` But even for properties which wouldn't be modified, wouldn't I have to use a getter method to access each property within an object anyway? Thereby dictating at least a 1 getter method to 1 property ratio? – marked-down Aug 21 '13 at 08:12
  • If this data need to be accessed from the outside then allways use an accessor. The calling code don't have to know how that data is retrieved. By using a getter, you can get the data from a db, a file, or from something else. By using directly the variable, you can't change how the data is retrieved without major refactoring. – Atrakeur Aug 21 '13 at 08:15
4

The choice is up to you. Other important features of PHP 5 to consider are magic getter/setters:

http://www.php.net/manual/en/language.oop5.overloading.php#object.set http://www.php.net/manual/en/language.oop5.overloading.php#object.get

The magic of this is that you are able to do something like the following and decide where to get/set variables without having to declare them beforehand:

Class Foo {
    private $data = array();

    function __set($name,$val) {
       $this->$data[$name] = $val;
    }
    function __get($name) {
       if (array_key_exists($name, $this->data)) {
        return $this->data[$name];
    }
    else {
        return null;
    }
}

Voila, something like this now happens automagically:

$fee = new Foo(); $fee->bar = 42;

Zam
  • 2,880
  • 1
  • 18
  • 33
Matt
  • 71
  • 4
4

If you don't use getters and setters in a language like PHP, which is not type safe, then how are you going to ensure the type of the object's property is correct?

I may be missing the point completely, but if you need access to a property from outside of the object, I think it's still the best option to use accessors...

Also, as Juon Mendes mentions: some languages offer you to intercept when the properties themselves are being addressed. This may also be coming to PHP

You could even have a public setter, and a protected getter:

class TimePeriod {
    protected $Seconds = 3600;

    public $Hours {
        get { return $this->Seconds / 3600; }
        set { $this->Seconds = $value * 3600; }
    }

    // This property is read only as there is no setter
    public $Minutes {
        get { return $this->Seconds / 60; }
    }

    /* public getter, protected setter */
    public $Milliseconds {
        get { return $this->Seconds * 1000; }
        protected set { $this->Seconds = $value / 1000; }
    }
}
NDM
  • 6,731
  • 3
  • 39
  • 52
  • To save others some time, the mentioned "This may also be coming to PHP", 2012/2013 proposal was: declined, vote failed. – imme Apr 05 '19 at 07:29
2

IMO using getters and setters is a good practice and increases code readability too. Apart from checking the value while setting, there is another example, consider if u call getMoviesList(). Now this get method can be implemented in anyway, it can get movies list from the local db, get it from the online web service and so on... So the code making the decision maybe inside this function. Wherever u call it from, u don't care about the location and how it gets it. U just get the movies list.

Jazib
  • 1,200
  • 1
  • 16
  • 39