不使用setter和getter真是错吗?

时间:2009-04-30 18:19:16

标签: php oop

我是PHP的新手。出于某些原因,在其他类型的编程语言(如JAVA)中,我对使用每个变量的setter和getter没有任何问题,但是当我在PHP编程时可能因为它非常灵活,感觉有点浪费时间。在大多数时候将类属性设置为公共并且像这样操纵它们感觉更简单。问题在于,当我这样做的时候,我觉得我做错了什么并且反对OO原则。

不使用setter和getter真是错吗?为什么或者为什么不?你们大部分时间都是这样做的?

7 个答案:

答案 0 :(得分:21)

不使用属性访问器的主要问题是,如果您发现以后需要将字段更改为属性 - 例如,使其成为子类中的计算属性 - 您将破坏您的客户端API。对于已出版的图书馆,这是不可接受的;对于一个内部的,只是做了很多工作。

对于私人代码或小型应用程序,只需将它放在一边即可。 IDE(或文本编辑器)将允许您生成访问器样板并使用代码折叠隐藏它。这可以说使得使用getter和setter非常容易。

请注意,某些编程语言具有合成默认字段+ getter + setter的功能 - Ruby通过元编程实现,C#具有自动实现的属性。 Python允许您覆盖属性访问,完全回避这个问题,让您将属性封装在需要它的子类中,而不必事先打扰它。 (这是我最喜欢的方法。)

答案 1 :(得分:17)

getter或setter的关键在于你仍然可以在一个地方为你的字段修改添加逻辑,而不是你想要修改或检索字段的每个地方。您还可以在课堂上获得对该领域的控制权。

答案 2 :(得分:15)

如果我们在这里严格谈论PHP,而不是关于C#,Java等(编译器将优化这些东西),我发现getter和setter浪费资源,你只需要代理它的值私人领域,别无其他。

在我的设置中,我制作了两个糟糕的类,一个有五个私有字段,由五个getter / setter对封装,代理字段(看起来几乎完全像java代码一样,有趣的话),另一个用五个公共字段,并在创建实例后调用memory_get_usage()。带有getter / setter的脚本使用了59708字节的内存,带有公共字段的脚本使用了49244字节。

在任何重要大小的类库(例如网站框架)的上下文中,这些无用的getter和setter可以为内存添加巨大的黑洞。我一直在为我的雇主用PHP开发一个框架(他们的选择,不是我的。如果我有选择但我已经说过,PHP并没有对我们施加任何不可逾越的限制)我会不会使用它。当我重构时使用公共字段而不是getter / setter的类库,整个shebang至少每个请求使用的内存减少了25%。

__get(),__ set()和__call()'magic'方法真正为处理界面更改而发光。当您需要将字段迁移到getter / setter(或getter / setter到字段)时,它们可以使该过程对任何相关代码透明。使用解释语言,即使对Eclipse PDT或Netbeans提供的代码敏感性有相当好的支持,也很难找到字段或方法的所有用法,因此神奇的方法对于确保旧接口仍然委托给新的接口很有用。功能。

假设我们有一个使用字段而不是getter / setter开发的对象,我们想将一个名为'field'的字段重命名为'fieldWithBetterName',因为'field'不合适,或者不再准确描述使用,或者只是完全错了。并且说我们想要将一个名为“field2”的字段更改为从数据库中延迟加载其值,因为最初使用getter并不知道...

class Test extends Object {
    public $field;
    public $field2;
}

变为

class Test extends Object {
    public $fieldWithBetterName = "LA DI DA";
    private $_field2;

    public function getField2() {
        if ($this->_field2 == null) {
            $this->_field2 = CrapDbLayer::getSomething($this->fieldWithBetterName);
        }
        return $this->_field2;
    }

    public function __get($name) {
        if ($name == 'field')) {
            Logger::log("use of deprecated property... blah blah blah\n".DebugUtils::printBacktrace());
            return $this->fieldWithBetterName;
        }
        elseif ($name == 'field2') {
            Logger::log("use of deprecated property... blah blah blah\n".DebugUtils::printBacktrace());
            return $this->getField2();
        }
        else return parent::__get($name);
    }
}
$t = new Test;
echo $t->field;
echo $t->field2;

(作为旁注,'extends Object'位只是我用于几乎所有具有__get()和__set()声明的基类,当声明访问未声明的字段时会抛出异常)

您可以使用__call()向后退。这个例子非常脆弱,但清理并不难:

class Test extends Object {
    public $field2;

    public function __call($name, $args) {
        if (strpos($name, 'get')===0) {
            $field = lcfirst($name); // cheating, i know. php 5.3 or greater. not hard to do without it though.
            return $this->$field;
        }
        parent::__call($name, $args);
    }
}
如果setter必须做某事,或者getter必须延迟加载某些东西,或者确保已创建某些东西,或者其他什么,那么PHP中的getter和setter方法是好的,但是如果它们什么也不做则它们是不必要和浪费的除了代理该字段外,特别是使用上述一些技术来管理接口更改。

答案 3 :(得分:7)

我可能不会在这个上获得很多赞成,但是个人吸气,甚至更多的定形者对我来说感觉像是一个代码味道。设计应该是行为驱动,而不是数据驱动。当然,这只是一种意见。如果你有一个依赖于另一个对象的特定数据字段的对象,这是非常紧密的耦合。相反,它应该取决于该对象的行为,该行为远不如其数据脆弱。

但是,是的,就像这个原因一样,getter和setter之类的属性是直接依赖于一个字段的一个步骤。它不那么脆,并且放松了物体之间的耦合。

答案 4 :(得分:3)

您是否考虑过使用魔术函数__set / __ get?使用它们,您只需2个函数即可轻松合并所有getter / setter函数!

答案 5 :(得分:2)

有一种方法可以模拟get / set而不实际使用get / set函数类,所以你的代码仍然很整洁:

$person->name = 'bob';
echo $person->name;

看看我编码的this class

通常,在使用此类时,您将声明所有属性受保护(或私有)。如果您想要在属性上添加行为,比如在“name”属性上添加strtolower()+ ucfirst(),那么您需要做的就是在类中声明受保护的set_name()函数,行为应该自动获取。使用get_name()可以完成相同的操作。

// Somewhere in your class (that extends my class).
protected function set_name($value) { $this->name = ucfirst(strtolower($value)); }
//

// Now it would store ucfirst(strtolower('bob')) automatically.
$person->name = 'bob';

P.S。 另一个很酷的事情是你可以组成不存在的字段,如

echo $person->full_name;

没有这样的字段(只要有一个get_full_name()函数)。

答案 6 :(得分:1)

如果你在脚本中经常访问这些变量,并且经常更新yoru类,你应该使用setter和getter,但是如果你不这样做,当你改进你的类时,你必须更新所有使用这个变量的文件。

第二个主要原因是你不应该直接访问变量,因为类结构可能会改变,而且这些数据可能会有所不同。当你从类中获取数据时,你不应该关心如何生成这些数据.Class有关心这些数据处理,所以你只关心你会得到什么。