php面向对象编程中是禁止在对象外直接访问由private所定义的私有属性,但是在类中添加魔术方法__set(),__get(),__isset(),__unset()后可间接访问对象中的私有属性,为什么不直接定义为public访问属性呢?这样的好处是可以在魔术方法中定义一些规则,过滤对象外的一些非法数据,比如说一个人的年龄不可能是600岁,人的性别不可能是“苹果”、“石头”之类等等。
<?php class Person{ private $name; private $sex; private $age; /** php的构造方法是不能重写的,因为一个类中方法名只能是唯一且不重复的, 在构造方法中对参数设置初值,相当于其它语言的构造方法重写。 */ function __construct($name = '小可爱', $sex = '男', $age = 3){ $this->name = $name; $this->sex = $sex; $this->age = $age; } /** 魔术方法:__set(属性名, 属性值) */ public function __set($propertyName, $propertyValue){ if($propertyName == 'sex'){ if(!($propertyValue == '男' || $propertyValue == '女')) return; } if($propertyName == 'age'){ if($propertyValue < 1 || $propertyValue > 120) return; } $this->$propertyName = $propertyValue; } /** 魔术方法:__get(属性名) */ public function __get($propertyName){ if($propertyName == 'sex') return '保密'; if($propertyName == 'age'){ if($this->age > 30) return $this->age - 6; } return $this->$propertyName; } /** 魔术方法:__isset(属性名) */ public function __isset($propertyName){ if($propertyName == 'name') return false; return isset($this->$propertyName); } /** 魔术方法:__unset(属性名) */ public function __unset($propertyName){ if($propertyName == 'name') return; unset($this->$propertyName); } public function say(){ echo '姓名:' . $this->name . ',性别:' . $this->sex . ',年龄:' . $this->age . '<br>'; } } //实列化并且初始化对象 //$person = new Person; $person = new Person('孙悟空', '男', 580); echo "<strong style=\"color:#789\">初始化私有属性</strong><br>"; $person->say(); //在对象外给对象内的私有属性赋值 //魔术方法 __set() 的使用 $person->name = '孙晓雨'; $person->sex = '女'; $person->age = 32; echo "<br><strong style=\"color:#789\">__set()修改私有属性</strong><br>"; $person->say(); echo "<br><strong style=\"color:#789\">__get()获取私有属性</strong><br>"; //在对象外获取对象中的私有属性 //魔术方法 __get() 的使用 echo "姓名:" . $person->name . ",性别:" . $person->sex . ",年龄:" . $person->age; echo "<hr>"; //魔术方法 __isset() 的使用 var_dump(isset($person->name)); var_dump(isset($person->sex)); var_dump(isset($person->age)); echo "<hr>"; //魔术方法 __unset() 的使用 unset($person->name); unset($person->sex); unset($person->age); var_dump(isset($person->name)); var_dump(isset($person->sex)); var_dump(isset($person->age)); echo "<br>"; $person->say();
代码执行后的效果:
这里有一个小细节,可能是php版本的原因,有的版本在调用属性时,如果没有属性,不会调用魔术方法__get(),上面执行后的最后一行应该是:
姓名:孙晓雨,性别:,年龄:
但是我用的版本在调用属性时,如果没有属性就调用了魔术方法__get(),这给代码在不同版本迁移时带来难度。