魔术方法有哪些
- __construct:构造方法
- __destuct:析构方法
- __call:在对象中调用一个不可访问的方法时。__call()会被调用
- __callStatic:
- __get:调用不可访问的属性
- __set:给不可访问的属性赋值或修改值
- __isset:
- __unset:
- __sleep:串行化的时候用,涉及到序列化
- __wakeup:反串行化的时候用,涉及到序列化
- __toString:
- __set_state:
- __clone:对象克隆前被调用
说明:
- 魔术方法都是系统提供的
- 所有的魔术方法,前面都是以__两个下划线
- 我们在自定义函数时,不建议已经能用两个_开始
- 魔术方法是在满足某个条件时,系统自动调用
访问控制修饰符的基本知识
访问修饰符包括:
- public:公有,被定义该修饰的成员可以在任何地方被访问
- protected:受保护的,被定义该修饰符的成员可以被自身及其子类和父类访问
- private:私有。被定义该修饰符的成员只能被其定义所在的类中访问
访问修饰符既可以修饰成员属性,也可以修饰成员方法
访问protected,private不可以直接访问,解决方法是编写一个public的成员方法,来操作protected和private属性
<?php class Person{ public $name; protected $age; private $sex; //构造方法 public function __construct ($name,$age,$sex){ $this->name = $name; $this->age = $age; $this->sex = $sex; } //访问protected属性 public function get_age(){ return $this->age; } //访问private属性 public function get_sex(){ return $this->sex; } } //创建对象 $p1 = new Person('张三',23,'男'); //访问各个属性 //访问公共属性public ,则可以直接访问 echo $p1->name; //访问protected,不可以直接访问,解决方法是编写一个public的成员方法,来操作protected属性 echo $p1->get_age(); //访问private,不可以直接访问,解决方法是编写一个public的成员方法,来操作private属性 echo $p1->get_sex();
魔术方法之 __get函数和__set函数
当开发者去使用不可以访问的属性时,系统就会调用__get方法
不可访问的属性指:
- 属性不存在
- 直接访问protected属性
- 直接访问private属性
当去给不可访问的属性直接赋值时,系统会调用__set方法
案例:
成员属性不可访问或者被私有,希望用对象名->变量名来赋值和取值
<?php class Monkey{ public $name; protected $food; //构造方法, public function __construct($name,$food){ $this->name = $name; $this->food = $food; } //魔术方法—__get() //$monkey_name代表形参,传过来的被私有或者受保护的属性名这里指的是$food public function __get($monkey_name){ //做一个判断 if(property_exists($this,$monkey_name)){ return $this->$monkey_name; }else{ return '没有该属性值'; } } //魔术方法- __set() public function __set($monkey_name,$monkey_val){ if(property_exists($this,$monkey_name)){ $this->$monkey_name = $monkey_val; }else{ return '该属性不存在'; } } } //创建对象 $monkey1 =new Monkey('小白','胡萝卜'); echo $monkey1->name; echo $monkey1->food; //修改属性值 $monkey1->name = '程序猿';//公共属性直接可以修改赋值 echo $monkey1->name; //默认protected的属性赋值时,会调用set方法 $monkey1->food = '夜宵'; $monkey1->food;
魔术方法之 __isset和__unset方法
- 当对不可访问的属性进行isset($对象名->属性),empty($对象名->属性)操作时,系统就会调用__isset函数
- 当对不可访问的属性进行unset($对象名->属性),系统就会调用__unset()函数
案例:unset($house->name);//Fatal error: Cannot access private property House::$name in D:\wamp64\www\issetunset.php on line 40
直接访问会提示不能调用被私有的属性,此时会自动调用__unset()魔术方法,在魔术方法中执行删除,然在打印,就会被删除掉
<?php //定义一个房子类House class House { //定义三个成员属性,价格Price、地址add、姓名name其中姓名私有private public $price; public $add; private $name; //定义构造方法 public function __construct ($price,$add,$name){ $this->price = $price; $this->add = $add; $this->name =$name; //魔术方法 } public function __isset($name1){ //property_exists()判断对象的属性或方法是否存在 if(property_exists($this,$name1)){ echo '存在'; }else{ echo 2; } } //魔术方法—__unset() public function __unset($name){ //判断成员属性是否存在 if(property_exists($this,$name)){ unset($this->$name); }else{ echo '不存在'; } } } $house = new House(1000,'陕西西安','张三'); //直接调用name返回的是2,被私有了无法赋值,用isset判断时要想用$对象名->属性名访问,就要使用魔术方法__isset(); if(isset($house->name)){ echo $house->name; }else{ echo 2; } //add属性是公开的,所以可以直接打印出来值 if(isset($house->add)){ echo $house->add; }else{ echo 2; } //unset()销毁成员属性 unset($house->name);//Fatal error: Cannot access private property House::$name in D:\wamp64\www\issetunset.php on line 40直接访问会提示不能调用被私有的属性,此时会自动调用__unset()魔术方法,在魔术方法中执行删除,然在打印,就会被删除掉 var_dump($house); ?>
魔术方法之__toString
当我们希望将一个对象当作字符串输出时,就会触发__toString魔术方法
魔术方法tostring
tostring没有形式参数
debug调试时,需要查看对象信息
案例:
<?php class Dog{ private $name; private $age; private $benling; //构造方法 public function __construct($name,$age,$benling){ $this->name = $name; $this->age = $age; $this->benling = $benling; } //魔术方法tostring //tostring没有形式参数 //debug调试时,需要查看对象信息 public function __toString(){ return '小狗的名字是 '. $this->name . '年龄为 ' . $this->age . '爱好为 ' . $this->benling; } } $dog = new Dog('藏獒',5 ,'看家'); //直接打印输出会触发toString魔术方法,如果不写会报错 echo $dog; ?>
魔术方法之__clone
当我们需要将一个对象完全的复制一份,保证两个对象的属性和属性值一样,但他们的数据空间是独立的,则可以使用对象克隆
说明:
- 当我们$对象1 = $对象2时会触发__clone方法
- 如果我们希望克隆,修改某个属性则在__clone方法中去修改即可
- 如果我们希望阻止克隆,只需要将__clone魔术方法申明为private即可
案例:
<?php class Sheep{ public $name; protected $food; public function __construct($name,$food){ $this->name = $name; $this->food = $food; } //__clone 魔术方法 //如果希望阻止克隆,则将__clone 申明为private public function __clone(){ //在克隆一个对象时,可以在这个__clone 函数中去修改某个属性,如果有必要的话 echo '复制一个'; } } $sheep1 = new Sheep('喜羊羊', '灰太狼'); //对象克隆会触发__clone的魔术方法,克隆只是值拷贝 $sheep2 = clone $sheep1; if($sheep1==$sheep2){ echo '相等'; } if($sheep1===$sheep2){ echo '全等'; }
魔术方法之__call函数
当我们调用要给不可访问的成员方法时,__call魔术方法就会被调用(不可访问即该成员方法不存在,成员访问被protected和private修饰)
__call魔术方法中,有两个参数
- 函数名:$mathod
- 参数 类型数组:$parameters
案例:
在类的外部调用不可访问的成员方法
<?php header('content-type:text/html; charset=utf-8'); class Sheep{ public $name; protected $food; //构造方法 public function __construct($name,$food){ $this->name = $name; $this->food = $food; } //展示对象都有哪些信息 public function show(){ echo '<br>小羊的名字是 ' . $this->name; foreach($this->food as $food){ echo '食物是 ' . $food; } } //定义一个受保护的方法 protected function hoddy($hoddy1,$hoddy2){ echo '<br>喜羊羊的第一个爱好是 ' . $hoddy1; echo '<br>喜羊羊的第二个爱好是 ' . $hoddy2; } //编写一个__call魔术方法,__call魔术方法会接收两个参数 /* @param $mathod_name 函数名 @param $parameters 就是参数,类型为array */ public function __call($method_name,$parameters){ //判断$this中是否有$method_name函数, if(method_exists($this,$method_name)){ return $this->$method_name($parameters[0],$parameters[1]); } else{ echo '没调用该函数'; } } } $sheep = new Sheep('喜羊羊' , array('青草','灰太狼')); $sheep->show(); //当我们直接调用受保护的方法时,会触发__call魔术方法 $sheep->hoddy('玩','打灰太狼'); ?>
实战:
有一个cat类,有年龄和名字两个属性,要求这两个属性全部都是public,cat类有一个方法jisuan($n1,$n2,$oper)可以计算+-*/,该方法是私有的,在类的外部$对象名->play(‘jisuan’,$n1,$n2,$oper)得到结果,该方法在类中没有定义
要求play是固定的,如果没有按规定写,则给出相应的错误提示
<?php header('content-type:text/html; charset=utf-8'); class Cat{ public $name; public $age; //构造方法 public function __construct($name,$age){ $this->name = $name; $this->age = $age; } //定义一个jisuan方法 private function jiSuan($n1,$n2 ,$oper){ $res = 0; //判断符号并计算 switch($oper){ case '+': $res = $n1 + $n2; break; case '-': $res = $n1 - $n2; break;case '*': $res = $n1 * $n2; break;case '/': $res = $n1 / $n2; break; default: echo '输入的符号错误,请重新输入'; } return $res; } //编写要给__call魔术方法 public function __call($method_name,$parameters){ //判断是否通过play方法调用 if($method_name == 'play'){ //判断jisuan()方法是否存在 if(method_exists($this,$parameters[0])){ return $this->$parameters[0]($parameters[1],$parameters[2],$parameters[3]); }else{ echo '你调用的'.$patameters[0].'不存在'; } }else{ echo '你调用的方式有问题'; } } } $cat = new Cat('tom',23); echo $cat->play('jiSuan',1,2,'*');
1234