6

Just a simple question. I've seen many cases where the code is implemented like the following:

class User
{
    private $id;
    private $firstname;
    private $lastname;

    public function __construct() { some code }

    public function getId() { return $this->id; }

    public function getFirstname() { return $this->firstname; }

    public function setFirstname($value) { $this->firstname = $value; }
}

// And properties are accessed like:
$user->getFirstname();
$user->getId();

So what is the reason of using private properties and having public getters, instead of making the properties public and accessing them directly like:

$user->firstname;

PS: Is it OK if I use the second method?

EDIT

Seems like I did not research well before asking this question (guess I used wrong keys to search on the topic). Here is another good answer to (almost) the same question: https://stackoverflow.com/a/1568230/1075534

Basically, for my case, one good reason to use getters and setters is to avoid changing 250 classes that directly access the property. So for example, imagine that I was not using a getter:

class User
{
    public $firstname = 'abc';
    public $lastname  = 'cde';
}

$user = new User(); 

echo $user->firstname . ' ' . $user->lastname;

Now, imagine that I want to change the behavior of my app and I decide to print names as capitalized. In this case then I would search each implementation (250 in this case :) and capitalize the output wherever I called the properties. But, rather If I used a getter then I would just change the getter method:

class User
{
    private $firstname = 'abc';
    private $lastname  = 'def';

    public getFirstname()
    {
        return ucfirst(strtolower($this->firstname));
    }

    public getLastname()
    {
        return  ucfirst(strtolower($this->lastname));
    }
} 

Also, bear in mind that a getter might not only gather information from a single property. Imagine the following:

class User
{
    private $firstname = 'abc';
    private $lastname  = 'def';

    public function getName()
    {
        return $this->firstname . ' ' . $this->lastname;
    }
}

For those who still have questions on this matter, I suggest them reading the material that Gordon provided and especially the answer that I've linked.

Community
  • 1
  • 1
Savas Vedova
  • 5,622
  • 2
  • 28
  • 44
  • You should read Code Complete 2. It has a great explanation on this subject and other Software Development concepts. – Gohn67 Jun 21 '13 at 10:00

3 Answers3

10

Using Accessors satisfies the Uniform Access Principle.

Quoting Wikipedia:

The Uniform Access Principle was put forth by Bertrand Meyer. It states "All services offered by a module should be available through a uniform notation, which does not betray whether they are implemented through storage or through computation." This principle applies generally to object-oriented programming languages. In simpler form, it states that there should be no difference between working with an attribute, precomputed property, or method/query.

In his blog, Fowler explains

It effectively means that a client of the person should neither know nor care whether the age is stored or computed. This gives the person object the flexibility to change between the two easily as well as removing what is usually an unnecessary concern from the client. It's an important part of encapsulation - or at least the data-hiding aspect of encapsulation.

To illustrate the point, imagine a class like this:

class Now
{
    public $timestamp;

    public function getTomorrow()
    {
        return strtotime('+1 day', $this->timestamp);
    }

 // … more code

When you do it this way, you are forcing the developer using that class to know the implementation details. To get the now's timestamp, the developer has to do

echo $now->timestamp;

whereas to get the computed timestamp for tomorrow, the developer has to do

echo $now->getTomorrow();

But the developer shouldn't need to care, so if you want to follow the UAP, you will provide an Accessor to get the timestamp. And funnel all access through methods.

Doing so also has the additional benefit of a more stable API. Imagine you need to change the implementation detail later in the project and turn timestamp into a DateTime object. Your class now looks like this:

class Now
{
    public $dateTime; // <-- no longer just a timestamp

    public function getTomorrow()
    {
        return strtotime('+1 day', $this->dateTime->getTimestamp());
    }

 // … more code

Now any developer that previously used $now->timestamp will have to change their consuming code to accomodate for that change. Whereas when you had used a Getter right from the start, it wouldn't be a problem at all, because the Getter would have made sure that it returned the timestamp. To further prove that point, note how the developer would not have to change anything to consume getTomorrow(). Although internally we changed the details, the public API still behaves the same.

Note that UAP is just a guideline. Modern IDEs make it dirt easy to generate Accessors and Mutators for you, so it's easy to follow. But it's not an absolute truth. If you can reasonably justify not following it, then don't follow it and use public properties. But it should be an informed decision.

However, in general, you want to avoid Getters (and Setters) anyway and just tell your objects what to do. This will give a much slimmer API. If your API has lots and lots of Getters, chances are you are scattering code that really should be inside the object into the consumers.

Gordon
  • 312,688
  • 75
  • 539
  • 559
  • Thanks @Gordon, really great answer. I've been reading all the material you've provided. But I still have a question. I primarily asked this question for a User class that I was going to write. Since it may have many properties (like firstname, lastname, email, hash, created etc...), and considering that I decide to follow the UAP principle, I will end having lots of getters and setters. I believe that in this case there is no bad if I avoid getters and setters, right? – Savas Vedova Jun 21 '13 at 10:52
  • @SavasVedova If the class is a data structure only, then *maybe*. But I suggest not to question whether you should follow it, but rather question why you wouldn't when following it future proofs your code and it's so easy to generate them automatically. – Gordon Jun 21 '13 at 11:00
2

When a variable is declared public, it is accessible from any class making it easier for you as a programmer to use; thus explaining your desire to use the second method you described. However, some variables need to be declared private for security reasons (also it is sometimes seen as a good practice). The fact that we declare them privatemake them only accessible in their own class. If You however need to use them in a function in another class then you need to follow the first method you described .

user2497624
  • 159
  • 9
2

using a getter makes it read-only.

(that's the only conceptual difference. a language could easily allow interfaces to be defined in terms of properties as well as methods. naming conventions are not really fundamental.)

necromancer
  • 23,916
  • 22
  • 68
  • 115