Getters and Setters can only "walk" together?

16

I am studying object orientation and am having some questions on the encapsulation part. For example:

Class Url {

    private $url;

    public function setUrl($url) {

        if (filter_var($url, FILTER_VALIDATE_URL)) {
            $this -> url = $url;
        } else {
            $this->url= false;
        }
    }

    public function getUrl(){

        return $this->url;

    }


}

As I need to validate the URL I've created this setter , since it's a better practice than doing validation in the constructor, correct?

I will use it outside the class, but this getter does not, so do I really need to create both? Why could I use the $url variable in the class context, since I will only use it within the same class.

Taking this question, I understood that I would only create the setter / getter if I were to change the value of the variable throughout the application, correct? Otherwise I could simply "build" it in the constructor? Example:

public function __construct ($url) {

    $this->url = $url;

}
    
asked by anonymous 21.12.2014 / 07:30

2 answers

12
In Object Orientation getters and setters participate in the Information Concealment Principle , which ensures that a property is available for reading or recording only under certain circumstances:

  • Private: Only those who have defined
  • Protected: Who defined and who extends it
  • Public: Everyone

However, both getters and setters are optional. And this allows you to simulate read-only and even just-write properties (if there is any practical application for that) which, so far, can not be done automatically at the interpretation level:

In your example, setting url property visibility to private ensures no one can change their value directly.

If it had public visibility, this could occur:

$url = new Url;

$url -> url = 'Oi, eu sou Goku!';

And anything that depends on a valid URL would fail.

So, you have to ensure that only URLs are entered as value for this argument because through a setter , you can validate.

If this value needs to be read in the context of the instance, you must add a getter . But if this argument can not be changed in the same context, you do not need and should not have a setter because once you set the URL it should be maintained until the object is destroyed manually or at the end of the Request.

However, although the constructor of an object serves to construct the object (doh) it should not do everything by itself.

The ideal is to delegate the task of validating and assigning the property value through a setter .

But you're contradicting yourself!

Yes, it may look like this, but just as properties have configurable visibility, so are they for methods, so you can instead have a method specifically designed to validate and set a value for this property but not externally available:

class Url {

    private $url;

    public function __construct( $url ) {

        $this -> setUrl( $url );
    }

    private function setUrl( $url ) {

        if( filter_var( $url, FILTER_VALIDATE_URL ) === FALSE ) {

            throw new InvalidArgumentException(

                sprintf( '%s is not a valid URL', $url )
            );
        }

        $this -> url= $url;
    }

    public function getUrl(){
        return $this -> url;
    }
}

Notice, too, the difference in this code in relation to yours. You accept an invalid URL which forces you to manually check if this value is a valid URL when your class needs to use the value of that property, again, again, and again.

And this defeats the purpose of a setter which is to ensure that the information passed is reliable.

In this example, if the URL does not pass validation I trigger a InvalidArgumentException , a specific natively available exception to be used when a given argument is invalid for the purpose of whoever defined it.

Good studies:)

    
21.12.2014 / 12:55
12

No, you can use either of them individually as needed. Good practice is one that you need and are correct.

If you are not going to use the getter publicly, do not create it.

In fact, if you also do not have to assign a value to a property publicly, which makes a lot of sense if you do not have a getter , then you also do not have to create a setter . If you just need to initialize a class member, and eventually validate, do it in the constructor.

Class Url {
    private $url;

    public function __construct ($url) {
        if (filter_var($url, FILTER_VALIDATE_URL)) {
            $this -> url = $url;
        } else {
            $this->url= false;
        }
    }
}

Of course it depends on how you want to use this instance variable $url . I imagine that anything that is to manipulate it within the class does not depend on the validation placed in the constructor, otherwise it would be interesting to use a method that acts as an intermediary to access the variable. In general you can control the state of it more reliably within the class and do not need validation.

    
21.12.2014 / 09:42