我应该或不应该使用getter和setter方法吗?

时间:2013-08-21 07:57:57

标签: php oop getter-setter

好吧,这真的让我烦恼,我开始认为这一切都取决于个人选择,而不是提高效率或编写更好代码的特定方式:我应该还是不应该使用getter / setter PHP项目中的方法?到目前为止,我读过的答案相当矛盾,并不完全适合PHP,这不是一种编译语言。例如,在Stack Overflow上使用此问题(" Why use getters and setters?")。有很多很好的理由说明为什么我应该在我的代码中使用它们,但是所有的孩子评论都提到了Accessors are evil应该如何避免,并且在一些更令人不安的评论之间穿插,提到他们应该完全避免,因为它会破坏你的代码"。

所有我得到的是相互矛盾的答案,其中没有一个与解释的PHP环境相关。有人可以阐明为什么/为什么不在PHP中使用它们,以及它们的决定背后的理由?如果我们可以简单地将属性定义为私有或受保护并且无论如何都是真的重要:

  

封装吸气剂和固定剂提供的是可笑的薄

...引自" sbi" (为什么要使用getter和setter?)

就个人而言,我仍然不知道如何:

Class Foo {
    public $bar;

    function setBarType($val) {
       $this->bar = $val;
    }
}

$fee = new Foo();
$fee->setBarType(42);

优于此:

Class Foo {
    public $bar;
}

$fee = new Foo();
$fee->bar = 42;

7 个答案:

答案 0 :(得分:16)

您链接的博客文章以一个重要句子开头(强调添加):

  

代码中的每个getter和setter都代表无法封装并创建不必要的耦合。

封装是面向对象编程最重要的思想。它本质上归结为隐藏复杂性,方法是将它整齐地包装在类中。在一个理想的世界中,当你使用一个类时,你不应该知道关于它的内部工作或状态的任何。有些人(比如这个博客作者)会争辩说,拥有getter和setter已经是关于班级内部的太多信息了。在他们看来,一个类应该只有一些方法可以让我们告诉一个对象做某事,更不用说 它是怎么做的或它处于什么状态。使用一个setter不是“告诉对象做某事”,而是从外面篡改对象的状态。

而不是这样做:

$a = myObject();

// Querying object state, making a decision outside the object, and changing its state
if ($a->getWarbleFizz() < 42) {
    $a->setYourWarbleFizzTo(42);
}

// Gee, I hope I made the right decision...
$a->nowDoSomethingUseful();

你应该写这样的代码:

$a = myObject(42);
$a->doStuff();

或者这个:

$a = myObject();
$a->doStuff(42);

相关阅读:Tell, don't ask

答案 1 :(得分:12)

因为如果设置值的实现方式发生了变化(对数据库),则不必更改调用者。另一个例子是您可能需要在设置之前对值进行一些检查。

有一个方法可以拦截该变量的设置/获取,当它看起来不需要它时,它会使你的代码更加友好。

属性获取者

C#等语言和最新版本的JavaScript允许您拦截属性读取和写入,因此您可以使用支持它的语言中的属性。

对象观察者

某些语言允许您截取所有JavaScript's Object.watch的读取/设置或PHP's __get无法访问的属性。这允许您实现getter和setter,但是由于他们为每个属性访问创建的开销,您会受到性能影响。这个答案谈到了getter和setter的其他问题。 Best practice: PHP Magic Methods __set and __get

Getters和Setter都可以,但是......

制作样板吸气剂和制定者更好,但几乎和公共财产一样糟糕。如果任何人可以更改对象的状态(特别是具有多个属性),则它将无法很好地封装。 http://cspray.github.io/2012/05/13/stop-calling-them-getters-setters.html

答案 2 :(得分:7)

使用getter和setter的巨大好处是,只要你需要进行更改,你只需要修改getter和setter。

我将尝试用一个例子来解释:

protected $date;
public function getDate(){
    return $this->date;
}
public function setDate($date){
    $this->date = $date;
}

想象一下,有一个原因,日期应该总是增加一天。您必须在您访问班级成员的整个项目中进行搜索。

但是通过使用getter和setter,您可以将代码更改为:

protected $date;
public function getDate(){
    return $this->date;
}
public function setDate($date){
    $date = new DateTime($date);
    $date->modify('+1 day');
    $this->date = $date;
}

答案 3 :(得分:5)

一个OOP原则是封装。类负责此类中包含的所有变量。

通过设置公共变量,您将打破该原则。

通过创建一个存取器(setter),你可以通过在类之外更改该值来间接破坏该原理。

getter的优点是调用方法不需要关心如何检索数据。它只知道它将获得预期的数据,而这就是全部。这里封装原则受到尊重。

setter的优点是类在应用之前有机会检查新值。在一个完美的世界中,不需要访问器,因为一个类可以完全管理他的所有变量。在现实世界中,有时您需要设置一个值或从外部获取它。

接近完美世界的最佳方法是将加速器仅限于极少数必须修改的变量。如果可能,请检查设定值。

关于你的例子,第二个解决方案更好,因为你在php堆栈中保存了一个级别。您的访问器是无用的,因为您的变量无论如何都是公共的(因此,没有封装)并且不执行任何附加检查。但是在可能的情况下,您应该使用访问器来检查数据。如果您的应用程序中的其他任何地方都不需要这些数据,那么请不要使用任何访问者。

答案 4 :(得分:4)

选择取决于你。 PHP 5需要考虑的其他重要功能是魔术getter / setter:

http://www.php.net/manual/en/language.oop5.overloading.php#object.set http://www.php.net/manual/en/language.oop5.overloading.php#object.get

这样做的神奇之处在于,您可以执行以下操作,并决定在何处获取/设置变量,而无需事先声明它们:

Class Foo {
    private $data = array();

    function __set($name,$val) {
       $this->$data[$name] = $val;
    }
    function __get($name) {
       if (array_key_exists($name, $this->data)) {
        return $this->data[$name];
    }
    else {
        return null;
    }
}

Voila,现在这样的事情会自动发生:

$ fee = new Foo(); $ fee-&gt; bar = 42;

答案 5 :(得分:3)

如果你不使用PHP这样的语言中的getter和setter,这不是类型安全的,那么你如何确保对象属性的类型是正确的呢?

我可能完全忽略了这一点,但如果您需要从对象外部访问属性,我认为它仍然是使用访问器的最佳选择...

此外,正如Juon Mendes所提到的:某些语言可以让你在物业本身被解决时进行拦截。 This may also be coming to PHP

你甚至可以拥有一个公共的setter和一个受保护的getter:

class TimePeriod {
    protected $Seconds = 3600;

    public $Hours {
        get { return $this->Seconds / 3600; }
        set { $this->Seconds = $value * 3600; }
    }

    // This property is read only as there is no setter
    public $Minutes {
        get { return $this->Seconds / 60; }
    }

    /* public getter, protected setter */
    public $Milliseconds {
        get { return $this->Seconds * 1000; }
        protected set { $this->Seconds = $value / 1000; }
    }
}

答案 6 :(得分:2)

使用getter和setter的IMO是一种很好的做法,也可以提高代码的可读性。 除了在设置时检查值,还有另一个例子,考虑你是否调用getMoviesList()。现在这个get方法可以实现,它可以从本地数据库获取电影列表,从在线Web服务获取它等等......所以决策的代码可能在这个函数内部。无论你把它叫做什么,你都不关心它的位置和方式。你只需获取电影列表