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对象外访问私有属性,魔术方法__set(),__get(),__isset(),__unset()_初始化

 

  这里有一个小细节,可能是php版本的原因,有的版本在调用属性时,如果没有属性,不会调用魔术方法__get(),上面执行后的最后一行应该是:

  姓名:孙晓雨,性别:,年龄:

但是我用的版本在调用属性时,如果没有属性就调用了魔术方法__get(),这给代码在不同版本迁移时带来难度。