在PHP类中,为我们提供了一些魔术方法,每个魔术方法的命名开始于两个下横杠“__”,并会在特定的条件下,由PHP自动调用。根据不同的作用,魔术方法将分为以下三类:
构造和析构函数:
__construct(), __destruct()
重载:
__call(), __get(), __set(), __isset(), __unset()
(其中__isset(), __unset() 是PHP 5.1.0开始新增的)
其它:
__sleep(), __wakeup(), __toString(), __set_state(), __clone()
先介绍“重载”。
__get:当你试图获取一个非public的属性值时,__get将被自动调用。
__set:当你试图设置一个非public的属性值时,__set将被自动调用。
__isset:当你试图设置一个非public的属性值时,__set将被自动调用。
__unset:当你试图设置一个非public的属性值时,__set将被自动调用。
__call:当你试图调用一个未定义的方法时,__call将被自动调用。这里的“未定义的方法”包括没有权限访问的方法,例如私用方 法。
注意:
所有的Overloading方法必须不能声明为static型;
在PHP 5.0.X中,所有的Overloading方法必须定义为public类型。
__get(), __set(), __isset(), __unset()
由于申明为 private, protected 的属性只能在类的内部访问,所以PHP为我们提供了两个魔术方法:__get(), __set(),使得我们可以在类外部访问私有属性。当一个私有属性在类外部被访问时,PHP 会自动调用这几个魔术方法,从而可以对类的私有属性实现获取、设置、验证、销毁等操作。
这两个方法不是默认就有的,而是需要我们在类义类时,显式地定义这两个方法。
具体实现方法见下面例子:
class cls
{
private $atb1 = "private atb1"; // private只能在类内部访问,不包括子类。
protected $atb2 = "protected atb1"; //protected只能在类(包括子类)内部访问。
public $atb = "public atb1"; // 公有属性,可在类外部直接访问,不通过 __get()及__set() 。
private $x = array("a" => 1, "b" => 2, "c" => 3);
// 这个方法用来获取私有属性值的,当在类外部直接获取私有属性值的时候自动调用。
// 如果成员属性不封装成私有的,对象本身就不会去自动调用这个方法。
public function __get($name){
return "|---通过__get()获取的值----|" . $this->$name;
}
// 原理同上,该方法则用来设置私有属性的值。
public function __set($name, $value){
$this->$name = $value;
}
public function __isset($nm) {
echo "Checking if $nm is set/n";
return isset($this->x[$nm]);
}
public function __unset($nm) {
echo "Unsetting $nm/n";
unset($this->x[$nm]);
}
private function displayArray($arr) {
return print_r($arr);
}
//
public function __call($method, $array) {
if ($method == 'display') {
if (is_array($p[0])) {
$this->displayArray($p[0]);
} else {
var_dump($p[0]);
}
}
}
}
$clsa = new cls();
echo $clsa->atb1 . "
"; // 该语句将会自动调用 __get()方法,并将 atb1 做为参数,从而显示atb1的值。
//如果上面的类中未设置__get方法,该句将报错:Cannot access private property cls::$atb1
echo $clsa->atb . "
"; // 在类外部访问一个声明为public的属性时,将不会调用 __get()/__set() 。
$clsa->atb1 = "一个新的值"; // 该语句将利用__set函数来改变 $atb 的值
// atb1将直接做为 __set的第一个参数,而后面的值将做为其第二个参数,最终实现了为atb1设置一个新的值。
var_dump(isset($clsa->a)); // 访语句将调用类中的 __isset()函数,并将"a"做为基参数。
unset($clsa->atb); // 该方法将不会调用类中的 __unset(),因为 $atb 是一个公有属性。
$clsa->display(array('cat', 'dog', 'none')); //由于参数是个数组,所以该语句将调用私有方法displayArray();
$clsa->display('cat'); // 由于参数不是数组,所以该语句将调用 var_dump(),显示其值。
使用魔术方法的好处,就是对成员属性的访问可以实现单一入口。例如可能我们在设置属性的值时,还需要做一些其它的前期工作(验证、过滤或访问数组形式的私有属性等),如果对属性的设置只有一个入口(__set()),那我们就只需要在这一个入口加上这些代码就行了。同样道理,如果以后需要再修改,我们就只需要修改这一处。