Getter and Setter?

前端 未结 15 662
南方客
南方客 2020-11-22 16:47

I\'m not a PHP developer, so I\'m wondering if in PHP is more popular to use explicit getter/setters, in a pure OOP style, with private fields (the way I like):



        
相关标签:
15条回答
  • 2020-11-22 17:36

    There are many ways to create sourcecode in a netbeans-convention. This is nice. It makes thinks such easyer === FALSE. Just use the traditionel, specially if you are not sure which one of the properties should be encapsuled and which one not. I know, it is a boi.... pla... code, but for debugging-works and many other thinks it is the better, clear way. Dont spend to much time with thousend of arts how to make simple getters and setters. You cannot implement too some design patterns like the demeter-rule and so on, if you use magics. In specific situation you can use magic_calls or for small, fast and clear solutions. Sure you could make solutions for design-patters in this way too, but why to make you live more difficult.

    0 讨论(0)
  • 2020-11-22 17:38

    In addition to the already great and respected answers in here, I would like to expand on PHP having no setters/getters.

    PHP does not have getter and setter syntax. It provides subclassed or magic methods to allow "hooking" and overriding the property lookup process, as pointed out by Dave.

    Magic allows us lazy programmers to do more with less code at a time at which we are actively engaged in a project and know it intimately, but usually at the expense of readability.

    Performance Every unnecessary function, that results from forcing a getter/setter-like code-architecture in PHP, involves its own memory stack-frame upon invocation and is wasting CPU cycles.

    Readability: The codebase incurs bloating code-lines, which impacts code-navigation as more LOC mean more scrolling,.

    Preference: Personally, as my rule of thumb, I take the failure of static code analysis as a sign to avoid going down the magical road as long as obvious long-term benefits elude me at that time.

    Fallacies:

    A common argument is readability. For instance that $someobject->width is easier to read than $someobject->width(). However unlike a planet's circumference or width, which can be assumed to be static, an object's instance such as $someobject, which requires a width function, likely takes a measurement of the object's instance width.
    Therefore readability increases mainly because of assertive naming-schemes and not by hiding the function away that outputs a given property-value.

    __get / __set uses:

    • pre-validation and pre-sanitation of property values

    • strings e.g.

      "
      some {mathsobj1->generatelatex} multi
      line text {mathsobj1->latexoutput}
      with lots of variables for {mathsobj1->generatelatex}
       some reason
      "
      

      In this case generatelatex would adhere to a naming scheme of actionname + methodname

    • special, obvious cases

      $dnastringobj->homeobox($one_rememberable_parameter)->gattaca->findrelated()
      $dnastringobj->homeobox($one_rememberable_parameter)->gttccaatttga->findrelated()
      

    Note: PHP chose not to implement getter/setter syntax. I am not claiming that getters/setter are generally bad.

    0 讨论(0)
  • 2020-11-22 17:38

    After reading the other advices, I'm inclined to say that:

    As a GENERIC rule, you will not always define setters for ALL properties, specially "internal" ones (semaphores, internal flags...). Read-only properties will not have setters, obviously, so some properties will only have getters; that's where __get() comes to shrink the code:

    • define a __get() (magical global getters) for all those properties which are alike,
    • group them in arrays so:
      • they'll share common characteristics: monetary values will/may come up properly formatted, dates in an specific layout (ISO, US, Intl.), etc.
      • the code itself can verify that only existing & allowed properties are being read using this magical method.
      • whenever you need to create a new similar property, just declare it and add its name to the proper array and it's done. That's way FASTER than defining a new getter, perhaps with some lines of code REPEATED again and again all over the class code.

    Yes! we could write a private method to do that, also, but then again, we'll have MANY methods declared (++memory) that end up calling another, always the same, method. Why just not write a SINGLE method to rule them all...? [yep! pun absolutely intended! :)]

    Magic setters can also respond ONLY to specific properties, so all date type properties can be screened against invalid values in one method alone. If date type properties were listed in an array, their setters can be defined easily. Just an example, of course. there are way too many situations.

    About readability... Well... That's another debate: I don't like to be bound to the uses of an IDE (in fact, I don't use them, they tend to tell me (and force me) how to write... and I have my likes about coding "beauty"). I tend to be consistent about naming, so using ctags and a couple of other aids is sufficient to me... Anyway: once all this magic setters and getters are done, I write the other setters that are too specific or "special" to be generalized in a __set() method. And that covers all I need about getting and setting properties. Of course: there's not always a common ground, or there are such a few properties that is not worth the trouble of coding a magical method, and then there's still the old good traditional setter/getter pair.

    Programming languages are just that: human artificial languages. So, each of them has its own intonation or accent, syntax and flavor, so I won't pretend to write a Ruby or Python code using the same "accent" than Java or C#, nor I would write a JavaScript or PHP to resemble Perl or SQL... Use them the way they're meant to be used.

    0 讨论(0)
  • 2020-11-22 17:41

    I made an experiment using the magic method __call. Not sure if I should post it (because of all the "DO NOT USE MAGIC METHODS" warnings in the other answers and comments) but i'll leave it here.. just in case someone find it useful.


    public function __call($_name, $_arguments){
        $action  = substr($_name, 0, 4);
        $varName = substr($_name, 4);
    
        if (isset($this->{$varName})){
            if ($action === "get_") return $this->{$varName};
            if ($action === "set_") $this->{$varName} = $_arguments[0];
        }
    }
    

    Just add that method above in your class, now you can type:

    class MyClass{
        private foo = "bar";
        private bom = "bim";
        // ...
        // public function __call(){ ... }
        // ...
    }
    $C = new MyClass();
    
    // as getter
    $C->get_foo(); // return "bar"
    $C->get_bom(); // return "bim"
    
    // as setter
    $C->set_foo("abc"); // set "abc" as new value of foo
    $C->set_bom("zam"); // set "zam" as new value of bom
    


    This way you can get/set everything in your class if it exist so, if you need it for only a few specific elements, you could use a "whitelist" as filter.

    Example:

    private $callWhiteList = array(
        "foo" => "foo",
        "fee" => "fee",
        // ...
    );
    
    public function __call($_name, $_arguments){
        $action  = substr($_name, 0, 4);
        $varName = $this->callWhiteList[substr($_name, 4)];
    
        if (!is_null($varName) && isset($this->{$varName})){
            if ($action === "get_") return $this->{$varName};
            if ($action === "set_") $this->{$varName} = $_arguments[0];
        }
    }
    

    Now you can only get/set "foo" and "fee".
    You can also use that "whitelist" to assign custom names to access to your vars.
    For example,

    private $callWhiteList = array(
        "myfoo" => "foo",
        "zim" => "bom",
        // ...
    );
    

    With that list you can now type:

    class MyClass{
        private foo = "bar";
        private bom = "bim";
        // ...
        // private $callWhiteList = array( ... )
        // public function __call(){ ... }
        // ...
    }
    $C = new MyClass();
    
    // as getter
    $C->get_myfoo(); // return "bar"
    $C->get_zim(); // return "bim"
    
    // as setter
    $C->set_myfoo("abc"); // set "abc" as new value of foo
    $C->set_zim("zam"); // set "zam" as new value of bom
    

    .
    .
    .
    That's all.


    Doc: __call() is triggered when invoking inaccessible methods in an object context.

    0 讨论(0)
  • 2020-11-22 17:44

    Encapsulation is important in any OO language, popularity has nothing to do with it. In dynamically typed languages, like PHP, it is especially useful because there is little ways to ensure a property is of a specific type without using setters.

    In PHP, this works:

    class Foo {
       public $bar; // should be an integer
    }
    $foo = new Foo;
    $foo->bar = "string";
    

    In Java, it doesn't:

    class Foo {
       public int bar;
    }
    Foo myFoo = new Foo();
    myFoo.bar = "string"; // error
    

    Using magic methods (__get and __set) also works, but only when accessing a property that has lower visibility than the current scope can access. It can easily give you headaches when trying to debug, if it is not used properly.

    0 讨论(0)
  • 2020-11-22 17:45

    This post is not specifically about __get and __set but rather __call which is the same idea except for method calling. As a rule, I stay away from any type of magic methods that allow for overloading for reasons outlined in the comments and posts HOWEVER, I recently ran into a 3rd-party API that I use which uses a SERVICE and a SUB-SERVICE, example:

    http://3rdparty.api.com?service=APIService.doActionOne&apikey=12341234
    

    The important part of this is that this API has everything the same except the sub-action, in this case doActionOne. The idea is that the developer (myself and others using this class) could call the sub-service by name as opposed to something like:

    $myClass->doAction(array('service'=>'doActionOne','args'=>$args));
    

    I could do instead:

     $myClass->doActionOne($args);
    

    To hardcode this would just be a lot of duplication (this example very loosely resembles the code):

    public function doActionOne($array)
        {
            $this->args     =   $array;
            $name           =   __FUNCTION__;
            $this->response =   $this->executeCoreCall("APIService.{$name}");
        }
    
    public function doActionTwo($array)
        {
            $this->args     =   $array;
            $name           =   __FUNCTION__;
            $this->response =   $this->executeCoreCall("APIService.{$name}");
        }
    
    public function doActionThree($array)
        {
            $this->args     =   $array;
            $name           =   __FUNCTION__;
            $this->response =   $this->executeCoreCall("APIService.{$name}");
        }
    
    protected function executeCoreCall($service)
        {
            $cURL = new \cURL();
            return $cURL->('http://3rdparty.api.com?service='.$service.'&apikey='.$this->api.'&'.http_build_query($this->args))
                        ->getResponse();
        }
    

    But with the magic method of __call() I am able to access all services with dynamic methods:

    public function __call($name, $arguments)
        {
            $this->args     =   $arguments;
            $this->response =   $this->executeCoreCall("APIService.{$name}");   
            return $this;
        }
    

    The benefit of this dynamic calling for the return of data is that if the vendor adds another sub-service, I do not have to add another method into the class or create an extended class, etc. I am not sure if this is useful to anyone, but I figured I would show an example where __set, __get, __call, etc. may be an option for consideration since the primary function is the return of data.


    EDIT:

    Coincidentally, I saw this a few days after posting which outlines exactly my scenario. It is not the API I was referring to but the application of the methods is identical:

    Am I using api correctly?

    0 讨论(0)
提交回复
热议问题