2013-08-21 197 views
19

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

我得到的所有答案都是相互矛盾的,其中没有一个与解释的PHP环境相关。是否有人能够明白为什么/为什么不应该在PHP中使用它们,以及它们背后的理由?是否真的重要,如果我们可以简单地定义一个属性为私有或保护,而且反正:

封装getter和setter报价是可笑的薄

...从“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; 
+4

你有可能分配前检查'$ val',如果出现错误抛出异常,触发用户错误或只返回二传手(第一个建议)在您的第一个例子(实际上,这是封装的点)。 – Leri

+0

@Leri,这实际上很有道理。但这是否意味着我必须为类中的每个属性获取/设置方法,如果我有50个不同的属性会发生什么 - 每个属性都有一个getter/setter? – ReactingToAngularVues

+1

具有50种不同属性的类最可能违反SRP。无论如何,这是开发者的选择。例如,我从不使用DTO的getters/setter,而将它们用于DomainObjects,因为我仅将DTO用于映射数据(主要是反射),而在DomainObjects中,我需要确保具有_correct_数据。 – Leri

回答

11

因为如果执行的值设置如何更改(对于数据库),则不必更改调用者。另一个例子是你可能需要在设置之前对值进行一些检查。

有一种方法可以让你拦截变量的设置/获取,当它看起来不像你需要的时候这样做会让你的代码更友好。

属性获取

语言,如C#和JavaScript的最新版本允许你拦截财产阅读和写作,所以你可以在支持它的语言使用性能。

对象观察家

有些语言让你拦截所有JavaScript's Object.watchPHP's __get读/设置,或无法访问性能。这使您可以实现getter和setter,但是由于它们为每个属性访问创建的开销,因此您会受到性能影响。这个答案谈到了获取者和制定者的其他问题。 Best practice: PHP Magic Methods __set and __get

getter和setter都OK,但...

只是让样板getter和setter方法较好,但几乎是一样糟糕的公共属性。如果任何人都可以改变你的对象的状态(特别是具有多个属性),它将不会很好地封装。 http://cspray.github.io/2012/05/13/stop-calling-them-getters-setters.html

+0

好的,但是说我从数据库中获取大量信息,可能是10个不同的信息变量,是否必须为每个*变量设置getter/setter方法,还是只有从db传递的数组?因为如果是前者,我会发现代码变得非常复杂,速度非常快。 – ReactingToAngularVues

+0

这取决于你,这超出了这个问题的范围,我不能评论一个假设。另外stackoverflow.com不是这些问题的地方。程序员交换的是更多的开放式问题,如 –

+0

你也可以用PHP截取属性读写:http://www.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading。成员 – Marek

3

该选择取决于您。考虑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,$val) { 
     if (array_key_exists($name, $this->data)) { 
     return $this->data[$name]; 
    } 
} 

瞧,这样的事情现在怎么自动地:

$费=新的Foo(); $ fee-> bar = 42;

+2

魔法属性真的很慢,如果可以的话,避免它们 –

3

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

我可能会完全错过了点,但如果你需要访问从对象之外的财产,我认为它仍然使用存取的最佳选择...

此外,作为咒怨门德斯提到:当属性本身被解决时,有些语言会提供你拦截。 This may also be coming to PHP

你甚至可以有一个公共的二传手,和一个受保护的吸气剂:

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; } 
    } 
} 
4

一个伟大的利润使用getter和setter的是,当你需要做出改变,你只需要修改getter和二传手。

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

想象是有原因的日期应始终为一天增加。你将不得不在整个项目中搜索你的班级成员。

但是,通过使用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; 
} 
2

IMO使用getter和setter方法是一个很好的做法,提高了代码的可读性了。 除了在设置时检查数值之外,还有另外一个例子,考虑你是否拨打getMoviesList()。现在这个get方法可以被实现,它可以从本地数据库获取电影列表,从在线Web服务获取电影列表,等等......所以做出决定的代码可能在这个函数中。无论你来自哪里,你都不在乎这个地点,以及它是如何得到它的。 U只需即可获得电影列表

5

一个OOP principe是封装。一个类负责该类中包含的所有变量。

通过设置一个公共变量,你打破了这个principe。

通过创建一个访问器(setter),您可以间接打破该原则,让该类别以外的值更改。

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

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

接近完美的世界,最好的办法是accesors仅限制为必须进行修改很少的变量。如果可能,请检查设定值。

关于你的榜样,因为你保存在PHP堆栈一个级别的第二个解决方案是更好的。你的访问器是无用的,因为你的变量是公开的(所以没有封装)并且不执行任何额外的检查。但是,如果可能的话,你应该使用访问器来检查数据。如果数据在应用程序的其他地方不需要,那么不要执行任何访问器。

+0

'仅限于极少数必须修改的变量“ 但即使对于不会被修改的属性,我也不需要使用无论如何都可以使用getter方法访问对象中的每个属性?从而口述至少1个吸气方法到1个房产比率? – ReactingToAngularVues

+0

如果需要从外部访问这些数据,那么总是使用访问者。调用代码不必知道如何检索数据。通过使用getter,您可以从数据库,文件或其他内容中获取数据。通过直接使用变量,您不能在没有重大重构的情况下更改数据的检索方式。 – Atrakeur

15

您链接到开始有一个关键句的博客文章(强调):

每一个getter和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

相关问题