不使用setter和getter真是错吗?

lal*_*007 15 php oop

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

不使用setter和getter真是错吗?为什么或者为什么不?大多数时候你们是如何做到的?

mil*_*ose 21

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

对于私人代码或小型应用程序,可能只需要它.IDE(或文本编辑器)将允许您生成访问器样板并使用代码折叠隐藏它.这可以说使得使用吸气剂和定位器非常容易.

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


Tom*_*nto 17

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


Sha*_*obe 15

如果我们在这里严格谈论PHP,而不是关于C#,Java等(编译器将优化这些东西),我发现getter和setter浪费资源,你只需要代理私有字段的值什么都不做

在我的设置中,我制作了两个糟糕的类,一个有五个私有字段,由五个getter/setter对代表字段封装(看起来几乎完全像java代码,有趣的是),另一个有五个公共字段,并且调用了memory_get_usage()at创建实例后的结束.具有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;
}
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

(作为旁注,'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);
    }
}
Run Code Online (Sandbox Code Playgroud)

PHP中的getter和setter方法是好的,如果setter必须做某事,或者getter必须延迟加载某些东西,或确保已创建某些东西,或者其他什么,但如果它们除了代理之外什么也不做,那么它们是不必要和浪费的该领域,特别是使用上述一些技术来管理界面变化.


nig*_*ski 7

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

但是,出于这个原因,像getter和setter这样的属性直接依赖于对字段的依赖.它不那么脆,并且松散了物体之间的耦合.