1.什么是魔术方法?
魔术方法指的是系统在特定的时机自动调用的方法。
2.访问权限
在介绍魔术方法之前,先介绍一下PHP中的访问权限:
在PHP中一般有三个权限修饰符,并且权限修饰符是可选项,常见的权限修饰符包括public、private、protected。创建类时,可以省略权限修饰符,此时默认的修饰符为public。public、private、protected三者区别如下:
(1):一般情况下,属性和方法的默认选项是public,这意味着属性和方法的每个项从类内部和外部都可以访问。
(2):用关键字private声名的属性和方法则只能从类内部访问,也就是说只有类内部的方法才可以访问此关键字声名的类的属性和方法。
(3):用关键字protected声名的属性和方法也是只能从类内部访问,但是可以通过“继承”而产生的“子类”也是可以访问这些属性和方法的。
<?php
class Father {
public $name = "小明";
protected $age = 12;
private $sex = "男";
}
class Son extends Father {
public function info() {
echo "我的名字是".$this->name."<br />";
echo "我的年龄是".$this->age."<br />";
echo "我的性别是".$this->sex."<br />";
}
}
$xiaoming = new Son();
echo $xiaoming->info();
?>
输出结果如下:
3.常见的魔术方法及应用
(1):__get():触发时刻:对象在外部访问私有成员或者受保护时调用,该方法有一个参数,这个参数就是属性名。
<?php
class Person {
public $name = "小明";
protected $age = 12;
private $sex = "男";
}
$xiaoming = new Person;
echo $xiaoming->name;
echo $xiaoming->age;
echo $xiaoming->sex;
?>
当执行上面的代码时,发现除了打印出小明之外,其他两条语句都会报错,那是因为protected和private不能被外部直接访问。
<?php
class Person {
public $name = "小明";
protected $age = 12;
private $sex = "男";
public function __get($name) {
echo $name."<br />";
}
}
$xiaoming = new Person;
echo $xiaoming->name;
echo $xiaoming->age;
echo $xiaoming->sex;
?>
执行上述代码,结果如下所示
可以看出来,当访问name时并没有调用__get()魔术方法,原因是小明和后面的age并没有换行,这更加说明对象只有在外部访问私有成员或者受保护时才会调用,因此就可以在__get()魔术方法中进行条件判断来输出age和sex的值,代码如下:
<?php
class Person {
public $name = "小明";
protected $age = 12;
private $sex = "男";
public function __get($name) {
if ($name == "age") {
return $this->age;
} else {
return $this->sex;
}
}
}
$xiaoming = new Person;
echo $xiaoming->name;
echo $xiaoming->age;
echo $xiaoming->sex;
?>
这样就可以通过魔术方法__get()访问到之前protected和private修饰的变量的值了。
(2):__set():触发时刻:对象在外部设置私有成员或者受保护时调用,该方法有两个参数,分别为属性名和要设置的值。
<?php
class Person {
public $name;
protected $age;
private $sex;
}
$xiaoming = new Person;
$xiaoming->name = "小明";
$xiaoming->age = 12;
$xiaoming->sex = "男";
?>
当执行上述代码时,执行到$xiaoming->age = 12时会报错,说明protected不允许在外面更改变量的值,因此可以使用__set()来更改受保护变量(被protected和private修饰)的值。
<?php
class Person {
public $name;
protected $age;
private $sex;
function __set($name,$value) {
if ($name == "age") {
return $this->age = $value;
} else {
return $this->sex = $value;
}
}
}
$xiaoming = new Person;
echo $xiaoming->name = "小明";
echo $xiaoming->age = 12;
echo $xiaoming->sex = "男";
?>
执行结果如下:
因此可以得出,可以通过__set()魔术方法来修改被protected和private修饰的值了。
(3):__unset():触发时刻:对象在外部销毁私有或者受保护的成员属性时调用,该方法有一个参数,这个参数就是私有的成员属性名。
在外部可以通过__unset()来销毁对象中的public属性,那么能不能销毁对象中的private和protected属性呢?我们来做个例子
<?php
class Person {
public $name;
protected $age;
private $sex;
}
$person = new Person;
var_dump($person);
?>
可以看出有三个属性,然后使用__unset()魔术方法来销毁三个属性,如下列的代码:
<?php
class Person {
public $name;
protected $age;
private $sex;
}
$person = new Person;
unset($person->name);
unset($person->age);
unset($person->sex);
var_dump($person);
?>
通过结果可以看出,只能销毁name属性(因为name属性是用public来修饰的),无法销age和sex属性(因为他们俩分别是用protected和private来修饰的)
然后利用__unset()魔术方法来销毁私有或者受保护的属性,代码如下:
<?php
class Person {
public $name;
protected $age;
private $sex;
public function __unset($name) {
if ($name == "age") {
unset ($this->age);
} else {
unset ($this->sex);
}
}
}
$person = new Person;
unset ($person->name);
unset ($person->age);
unset ($person->sex);
var_dump($person);
?>
由此可见,将三个属性都销毁了。
下面的几种魔术方法不是很常用,因此在此做简要介绍,有兴趣可以自己下去练习,方法同上。
(4):__isset():触发时刻:对象在外部判断私有或者受保护的成员属性时调用,该方法有一个参数,这个参数就是私有的成员属性名。
(5):__construct:构造方法:触发时期:在创建对象时自动调用
(6):__destruct:析构方法:触发时期:在对象被销毁时被调用的
(7):__toString:触发时期:echo一个对象时触发,该函数需要return一个字符串
(8):__debugInfo:触发时期:var_dump一个数组时触发,该函数需要return一个数组
(9):__call:触发时期:当调用一个不存在对象方法的时候触发,需要两个参数,一个参数是函数名,另一个参数是一个数组,函数中所有的参数都被存放到这个数组中
(10):__callStatic:触发时期:当调用一个不存在静态方法的时候触发,需要两个参数,一个参数是函数名,另一个参数是一个数组,函数中所有的参数都被存放到这个数组中
(11):__sleep:触发时期:在序列化一个对象的时候调用,返回值必须是一个数组,数组中写你要序列的成员属性名
(12):__wakeup:触发时期:在反序列化一个对象的时候调用,反序列化成功之后,想要让对象执行一些初始化方法,可以写到这个函数中
(13):__clone:触发时期:在克隆一个对象时候调用,在这里可以对克隆出来的对象的属性做一些操作
(14):__autoload:(这是唯一一个写在类外的魔术方法)触发时期:new一个对象的时候,当期脚本没有这个类,那么就会触发这个方法,参数就是该类的类名字符串