PHP `__set` 和`__get` 的深入理解

引用一个偷学来的概念:

成员变量是一个“内”概念,反映类的结构构成。属性是一个“外”概念,反映的是类的逻辑意义。 成员变量没有读写权限的控制,而属性可以指定只读只写,或可读或可写。 成员变量不对读出做任何后处理,不对写入做任预处理,而属性可以。 public成员变量可以视作没有任何后处理读操作以及没有任何预处理写操作的属性,而private由于外部不可见,不符合属性的“外”概念,所以不能视为属性。 大多数情况,属性会由成员变量来表示,但是属性和成员变量没有必然的对应关系。

通常情况下,将类的成员变量定义为private这样好处一个是为了类的封装性,同时能体现良好的变成习惯。但是对于成员变量的读写操作是非常繁琐的,因此,在PHP5中定义了两个魔法方法,__set()和__get(),在读取一个不存在的成员变量时候,会自动调用_set和_get,这两个方法不是默认存在,需要我们手动添加到类中。

Python
class Fruit { private $color; private $weight; public function __set($name,$value){ $this->$name = $value; } public function __get($name){ return $this->$name; } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Fruit
{
     private $ color ;
     private $ weight ;
 
 
     public   function __set ( $ name , $ value ) {
         $ this -> $ name = $ value ;
     }
 
     public   function __get ( $ name ) {
         return $ this -> $ name ;
     }
 
 
}
 

以上类Fruit中有两个私有的成员变量,设置了__set和__get以后,可以直接通过下面这种方式对成员变量进行调用。

Python
$fruit = new Fruit(); $fruit->color = 'red'; echo $fruit->color;
1
2
3
4
$ fruit = new Fruit ( ) ;
$ fruit -> color = 'red' ;
echo $ fruit -> color ;
 

如果没有__set和__get,直接通过$fruit->color这种方式调用,则会出错。

利用这一特点,可以实现对单一属性的set和get操作,同时在读操作的时候进行后处理以及在写操作的时候进行预处理。

Python
class Fruit { private $color; private $weight; public function __get($name) // 这里$name是属性名 { $getter = 'get' . $name; // getter函数的函数名 if (method_exists($this, $getter)) { return $this->$getter(); // 调用了getter函数 } elseif (method_exists($this, 'set' . $name)) { throw new InvalidCallException('Getting write-only property: ' . get_class($this) . '::' . $name); } else { throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name); } } // $name是属性名,$value是拟写入的属性值 public function __set($name, $value) { $setter = 'set' . $name; // setter函数的函数名 if (method_exists($this, $setter)) { $this->$setter($value); // 调用setter函数 } elseif (method_exists($this, 'get' . $name)) { throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name); } else { throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name); } } public function setColor($value){ if(trim($value)){ $this->color = $value; } } public function getColor(){ return 'The color is ' . $this->color; } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class Fruit
{
     private $ color ;
     private $ weight ;
 
 
 
     public function __get ( $ name )                / / 这里 $ name是属性名
     {
         $ getter = 'get' . $ name ;                / / getter函数的函数名
         if ( method_exists ( $ this , $ getter ) ) {
             return $ this -> $ getter ( ) ;            / / 调用了 getter函数
         } elseif ( method_exists ( $ this , 'set' . $ name ) ) {
             throw new InvalidCallException ( 'Getting write-only property: '
                 . get_class ( $ this ) . '::' . $ name ) ;
         } else {
             throw new UnknownPropertyException ( 'Getting unknown property: '
                 . get_class ( $ this ) . '::' . $ name ) ;
         }
     }
 
/ / $ name是属性名, $ value是拟写入的属性值
     public function __set ( $ name , $ value )
     {
         $ setter = 'set' . $ name ;              / / setter函数的函数名
         if ( method_exists ( $ this , $ setter ) ) {
             $ this -> $ setter ( $ value ) ;            / / 调用 setter函数
         } elseif ( method_exists ( $ this , 'get' . $ name ) ) {
             throw new InvalidCallException ( 'Setting read-only property: ' .
                 get_class ( $ this ) . '::' . $ name ) ;
         } else {
             throw new UnknownPropertyException ( 'Setting unknown property: '
                 . get_class ( $ this ) . '::' . $ name ) ;
         }
     }
 
     public   function   setColor ( $ value ) {
         if ( trim ( $ value ) ) {
             $ this -> color = $ value ;
         }
     }
 
     public   function   getColor ( ) {
         return 'The color is ' . $ this -> color ;
     }
 
}
 

这样可以在属性写操作的时候,对属性赋值进行trim处理,对属性读的时候,添加了一个一个字符串。

Python
$fruit = new Fruit(); $fruit->color = ' red'; echo $fruit->color;
1
2
3
4
$ fruit = new Fruit ( ) ;
$ fruit -> color = '  red' ;
echo $ fruit -> color ;
 

打印结果如下:

The color is red

同样,Yii2框架中Object类就是适用这个特性实现对private成员变量的setter和getter。




  • zeropython 微信公众号 5868037 QQ号 5868037@qq.com QQ邮箱
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值