Getter and Setter?

2018-12-31 23:43发布

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):

class MyClass {
    private $firstField;
    private $secondField;

    public function getFirstField() {
        return $this->firstField;
    }
    public function setFirstField($x) {
        $this->firstField = $x;
    }
    public function getSecondField() {
        return $this->secondField;
    }
    public function setSecondField($x) {
        $this->secondField = $x;
    }
}

or just public fields:

class MyClass {
    public $firstField;
    public $secondField;
}

Thanks

15条回答
一个人的天荒地老
2楼-- · 2019-01-01 00:11

Well, PHP does have magic methods __get, __set, __isset & __unset, which is always a start. Alas proper (get it?) OO properties is more than magic methods. The main problem with PHP's implementation is that magic methods are called for all inaccessible properties. Which means you have to Repeat Yourself (eg. by calling property_exists()) in the magic methods when determining if name is actually a property of your object. And you can't really solve this general problem with a base class unless all your classes inherit from ie. ClassWithProperties, since PHP lacks multiple inheritance.

In contrast, Python new style classes gives you property(), which lets you explicitly define all your properties. C# has special syntax.

http://en.wikipedia.org/wiki/Property_(programming)

查看更多
宁负流年不负卿
3楼-- · 2019-01-01 00:12

Validating + Formatting/Deriving Values

Setters let you to validate data and getters let you format or derive data. Objects allow you to encapsulate data and its validation and formatting code into a neat package that encourages DRY.

For example, consider the following simple class that contains a birth date.

class BirthDate {

    private $birth_date;

    public function getBirthDate($format='Y-m-d') {
        //format $birth_date ...
        //$birth_date = ...
        return $birth_date;
    }

    public function setBirthDate($birth_date) {                   
        //if($birth_date is not valid) throw an exception ...          
        $this->birth_date = $birth_date;
    }

    public function getAge() {
        //calculate age ...
        return $age;
    }

    public function getDaysUntilBirthday() {
        //calculate days until birth days
        return $days;
    }
}

You'll want to validate that the value being set is

  • A valid date
  • Not in the future

And you don't want to do this validation all over your application (or over multiple applications for that matter). Instead, it's easier to make the member variable protected or private (in order to make the setter the only access point) and to validate in the setter because then you'll know that the object contains a valid birth date no matter which part of the application the object came from and if you want to add more validation then you can add it in a single place.

You might want to add multiple formatters that operate on the same member variable i.e. getAge() and getDaysUntilBirthday() and you might want to enforce a configurable format in getBirthDate() depending on locale. Therefore I prefer consistently accessing values via getters as opposed to mixing $date->getAge() with $date->birth_date.

getters and setters are also useful when you extend objects. For example, suppose your application needed to allow 150+ year birth dates in some places but not in others. One way to solve the problem without repeating any code would be to extend the BirthDate object and put the additional validation in the setter.

class LivingBirthDate extends BirthDate {

    public function setBirthDate($birth_date) {
        //if $birth_date is greater than 150 years throw an exception
        //else pass to parent's setter
        return parent::setBirthDate($birth_date);
    }
}
查看更多
不再属于我。
4楼-- · 2019-01-01 00:13

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.

查看更多
闭嘴吧你
5楼-- · 2019-01-01 00:13

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.

查看更多
余欢
6楼-- · 2019-01-01 00:17
class MyClass {
    private $firstField;
    private $secondField;
    private $thirdField;

    public function __get( $name ) {
        if( method_exists( $this , $method = ( 'get' . ucfirst( $name  ) ) ) )
            return $this->$method();
        else
            throw new Exception( 'Can\'t get property ' . $name );
    }

    public function __set( $name , $value ) {
        if( method_exists( $this , $method = ( 'set' . ucfirst( $name  ) ) ) )
            return $this->$method( $value );
        else
            throw new Exception( 'Can\'t set property ' . $name );
    }

    public function __isset( $name )
    {
        return method_exists( $this , 'get' . ucfirst( $name  ) ) 
            || method_exists( $this , 'set' . ucfirst( $name  ) );
    }

    public function getFirstField() {
        return $this->firstField;
    }

    protected function setFirstField($x) {
        $this->firstField = $x;
    }

    private function getSecondField() {
        return $this->secondField;
    }
}

$obj = new MyClass();

echo $obj->firstField; // works
$obj->firstField = 'value'; // works

echo $obj->getFirstField(); // works
$obj->setFirstField( 'value' ); // not works, method is protected

echo $obj->secondField; // works
echo $obj->getSecondField(); // not works, method is private

$obj->secondField = 'value'; // not works, setter not exists

echo $obj->thirdField; // not works, property not exists

isset( $obj->firstField ); // returns true
isset( $obj->secondField ); // returns true
isset( $obj->thirdField ); // returns false

Ready!

查看更多
心情的温度
7楼-- · 2019-01-01 00:18

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.

查看更多
登录 后发表回答