访问修饰符的意义

很多同学还不知到为什么有些属性要设置成private,这样设置导致外部不能简单的直接访问属性(如:$obj->property),好像吃力不讨好喔,那么我们来看看原因吧:

   访问修饰符和访问控制的意义 :本文主要讲解为何有些成员变量需要设置成私有的,为什么不能直接设置成public直接在外部访问,以及PHP魔术方法get()和set()的使用

先上一段代码好说明问题

class User {
    private $_salary;//私用属性命名加_
    //setter and getter
    public function getSalary() {//如果只有get,那么说明该 属性/成员变量 只是可读,不可写
        return $this->_salary;
    }
    public function setSalary($salary) {//如果只有set,说明该 属性/成员变量 只是可写,不可读
        $this->_salary = $salary;
    }
}
  • 如上,我们觉得好像private改成public也没什么大问题,但是如果有这样一个场景,调用代码中,多处调用了User的salary属性,有写的也有读的,但是有一天,你不想让调用者修改salary了(禁用写),那怎么办?要怎么保证调用者的代码中没有直接修改salary的代码?如果提供了setter,那么只要把setter删掉,一旦调用代码中有没清理干净的对salary进行写入/修改 的代码,那么就会抛出异常。而使用public $salary这种方式的话,改成private后,虽然是可以禁止写了但是连读取也被禁止了。
  • 对写入数据的操作/过滤,使用setter和getter,可以统一对写入/读取 进行操作或者过滤,比如要去掉写入数据中的空格,如果使用public,那么要在每个调用处写上trim(),但是我们无法保证每处都写上trim了。如果用setter,那么我们可以在setter中写一次trim即可,而且也保证对每次写入都会进行过滤,不会有遗漏。

注意:由于 get() 和 set() 是在遍历所有成员变量,找不到匹配的成员变量时才被调用。因此,其效率是低于直接访问成员变量的形式。在一些表示数据结构、数据集合等简单情况下,且不需读写控制等, 可以考虑使用成员变量作为属性直接访问,这样可以提高一点效率。
另外一个提高效率的技巧就是:使用 $k1 = $obj->getK1() 来代替 $k1 = $obj->K1 , 用 $obj->setK1($value) 来代替 $obj->K1 = $value 。 这在功能上是完全一样的效果,但是避免了使用 get() 和 set() ,相当于绕过了遍历的过程。

这里还要区分,在类里成员变量和属性的区别。成员变量和属性的区别与联系在于:

  • 成员变量是一个“内”概念,反映的是就类的结构构成而言的该你那。属性是一个“外”概念,反映的是类的功能逻辑意义而言的概念。
  • 成员变量没有读写权限控制,而属性可以指定为只读或只写,或可读可写。
  • 成员变量不对读出作任何后处理,不对写入作任何预处理,而属性则可以。
  • public成员变量可以视为一个可读可写、没有任何预处理或后处理的属性。 而private成员变量由于外部不可见,与属性“外”的特性不相符,所以不能视为属性。
  • 虽然大多数情况下,属性会由某个或某些成员变量来表示,但属性与成员变量没有必然的对应关系, 比如与非门的 output 属性,就没有一个所谓的 $output 成员变量与之对应。

为了更形象,我们看个例子

    class NotAndGate {
        private $_k1;
        private $_k2;

        public function setK1($value) {
            $this->$_k1 = $value;
        }

        public function setK2($value) {
            $this->$_k2 = $value;
        }

        public function getOutput() {//与非门有两个输入,当两个输入都为真时,与非门的输出为假,否则,输出为真。
            if ( !$this->_k1 || !$this->_k2 ) return true;
            elseif ($this->_k1 && $this->_k2) return false;
        }
    }

上面的代码中,与非门类有两个成员变量, $_k1$_k2但是有3个属性,表示2个输入的 key1key2 ,以及表示输出的 output
由于我们知道,属性一般是通过$obj->property方式来访问的,但是这里根本没有output这个成员变量呀?那还怎么访问呢?
没错,这时候就要靠我们的魔术方法__get()来配合getter了,上__get()的代码:

    public function __get($name) {
        $getter = 'get' . $name;//如此,当调用$obj->output属性时,就会去调用getOutput(),以达到具有output属性的效果
        if (method_exists($this, $getter)) {
            return $this->$getter();
        } elseif (method_exists($this, 'set'.$name)) {
            echo '只存在setter,也即该属性为只写';
        } else {
            echo '无' , $name , '属性';
        }
    }

如有什么错误,欢迎提出、讨论,大家共同进步 ^_^

参考:http://www.digpage.com/property.html

原文链接:http://blog.zjien.com/2016/06/06/accessing...

《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 2
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!