Can Getters and Setters only "walk" together?

I am studying object orientation and I am having some doubts in 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;

    }


}

How do I need to validate the URL I created this setter , since it is 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 variable $url in the context of the class, since I will only use it inside the class even.

Taking advantage of 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 just "build it" in the constructor? Example:

public function __construct ($url) {

    $this->url = $url;

}
Author: Maniero, 2014-12-21

2 answers

In object orientation getters and setters participate in the principle of information concealment , which ensures that a property is available for reading or writing only in certain circumstances:

  • Private: only who defined
  • Protected: who defined and who extended it
  • Public: everyone

However, both getters and setters are optional. And this allows you to simulate read-only and even write-only properties (if there is any practical application for this) which, until now, cannot be done automatically at the level of interpretation:

In your example, setting property visibility Url:: url urlto private ensures that no one can change its value directly.

If it had visibility public , it could occur:

$url = new Url;

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

And anything that depends on a valid URL would fail.

Thus, you have to ensure that only URLs are reported as a 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 that argument cannot be changed in the same context, you don't need and shouldn't even have a setter because once the URL is defined it must be kept the same 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 alone.

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

but you are contradicting yourself!

Yes, it may look like this, but just as properties have visibility configurable, so they are for methods, so you can instead have a method specifically created to validate and set a value to that property, but that is 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 from yours. You accept an invalid URL which forces you to manually check if that value is a valid URL when your class needs to use the value of that property, again, again and again.

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

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

Good studies:)

 13
Author: Bruno Augusto, 2017-07-10 12:25:27

No, you can use either of the two in isolation as per your need. Good practice is the one you need and is correct.

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

In fact if you also don't need to assign value to a property publicly, which makes a lot of sense if you're not going to have a getter, then you don't have to create a setter either. If you only need to initialize one member of the class, and eventually validate, do 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;
        }
    }
}

I put on GitHub for future reference.

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

 12
Author: Maniero, 2019-01-17 11:48:38