3

In OO programming would it be looked down upon to use the magic methods __get() and __set(), do these cause encapsulation to leak out of a class? For example:

class User {
    private $username;
    private $password;

    public function __set($name,$value) {
        $this->$name = $value;
    }

    public function __get($name) {
        return $this->$name;
    }
}

This effectively makes private/protected variables public.

Pitchinnate
  • 7,517
  • 1
  • 20
  • 37
  • 2
    Nope! It depends of implementation. – felipsmartins Jun 03 '14 at 16:20
  • 1
    `__get` and `__set` are only called on "inaccessible properties". `password` is *technically* "inaccessible" since it's `private`. So when you access `password`, `__get()` is called. Doing this *can* "leak" `private` variables. Question is... why would you ever add these methods to your class like that in the first place? If you need `__get()` and `__set()` methods, one common way is to add a `private $data = array()` and have them access that array. `$this->data[$name] = $value;` http://www.php.net/manual/en/language.oop5.overloading.php#example-228 – gen_Eric Jun 03 '14 at 16:24
  • 1
    __get, __set, __call, and __invoke are basically PHPs way of implementing [operator overloading](http://en.wikipedia.org/wiki/Operator_overloading). While this isn't entirely true (since accessible properties won't have the operator overloaded) I feel its a good comparison since if you are using __get and __set correctly then you would use them in the same situations you would use operator overloading. Basically, you use it when it makes sense for your object to behave this way but without breaking incapsulating. – echochamber Jun 03 '14 at 17:06

3 Answers3

5

Your code:

class User {
    private $username;
    private $password;

    public function __set($name,$value) {
        $this->$name = $value;
    }

    public function __get($name) {
        return $this->$name;
    }
}

is totally unnecessary in this case.

Encapsulation does not mean "a bunch of getters and setters". You can just refactor it to:

class User {
    public $username;
    public $password;
}

and as far as encapsulation is concerned, they are equivalent.

In general __get and __set have some uses, but if you can do without, you should (especially considering that they are "considerably slower" than normal method definitions).

Community
  • 1
  • 1
Shoe
  • 74,840
  • 36
  • 166
  • 272
  • I understand they are equivalent, so would that make it a bad idea for OOP considering encapsulation is fundamental concept for OOP? – Pitchinnate Jun 03 '14 at 18:39
  • @Pitchinnate Encapsulation is not made of getters and setters (as I said). `__get` and `__set` are not bad per se, they are bad if you use them when you don't need it. – Shoe Jun 03 '14 at 18:44
0

If you use it exactly that way then yes. The behaviour would be the exact same, you should just use public variables because this is faster in PHP.

Something for which a setter is usefull is to check the value before actually assigning the value:

public function __set($name, $value)
{
    switch($name)
    {
        case 'username':
          if(strlen($value) < 6 || strlen($value) > 30)
            throw new Exception();

          ...
          break;

        case 'password':
          //some security checks
          break;

        default: throw Exception('no property'.$name);
    }

    $this->$name = $value;
}
Jimmy T.
  • 4,033
  • 2
  • 22
  • 38
  • 2
    Please elaborate. Your answer is correct, but there isn't enough information here to help the person asking the question, and others that may find your answer. – Brad Jun 03 '14 at 16:42
  • @Brad Is it better now? – Jimmy T. Jun 03 '14 at 16:56
0

There is not a strictly YES/NO answer to this question. Instead, there is an explanation to it:

From a purely Object-Oriented perspective, yes this is a leaky encapsulation. Why? Consider a case where a class has many attributes, and each attribute has a getter and a setter. Now,if this class is used in a large and complex application, in many places and in many ways, then it becomes difficult to control the state of the object (attribute values), as it can be modified/changed in many ways in many location, THROUGH ACCESSORS (getters and setters). So, what is the solution? Well, in general, better design is to construct an object through a constructor. For example, the User class can be redesigned as this:

class User {
    private username;
    private password;

    // constructor
    public User(name, password) {
        this->username = name;
        this->password = password;
    }

    // other methods
}

In this new design, there is only one way to create an object of User type, with constructor. This guarantees that the object is created in a known way, in a controlled way, hence its behaviour known at any time, is predictable.

Considering the above argument, it is not the getters that make the encapsulation leaky, it is the setters, because they are modifiers; can modify the state of the object 1) outside the constructor 2) any time, other than the time of construction.

That all being said, there are situations where one has to provide getters and setters for a class. For example, certain object-relational frameworks require this, for them to be able to modify objects.

Nazar Merza
  • 3,365
  • 1
  • 19
  • 19