9.3 魔术方法
9.3.1 __set()和__get()方法
1. __set()方法
__set()方法在代码试图要给未定义的属性赋值时调用,或在类外部修改被private修饰的类属性时被调用。它会传递两个参数:属性名和属性值。
代码示例
<?php
class magic{
private $_name;
private $_age='22 years old';
function __set($key,$value){
echo 'execute__set method';
$this->$key=$value;
}
}
$obj = new magic();
echo $obj->_weight='55kg';//访问类中不存在的$_weight属性被__set()方法拦截
echo $obj->name='chenxiaolong';//在类外部修改private修饰的属性$_name被拦截
echo '</br>';
var_dump($obj);
程序输出
execute__set method55kgexecute__set methodchenxiaolong
object(magic)#1 (4) { ["_name":"magic":private]=> NULL ["_age":"magic":private]=> string(12) "22 years old" ["_weight"]=> string(4) "55kg" ["name"]=> string(12) "chenxiaolong" }
可见程序两次调用了 __set() 方法。
2. __get()方法
当在类外部访问被private或protected修饰的属性或者访问一个类中原来不存在的属性时被调用。使用示例如下:
<?php
class magic1{
private $__age='22 years old';
protected $__height='170cm';
function __get($key){
echo 'execute __get() method.';
//var_dump($key);
$oldKey=$key;
if(isset($this->$key)){
return $this->$key;
}
$key='_'.$key;
//var_dump($key);
if(isset($this->$key)){
return $this->$key;
}
$key='_'.$key;
var_dump($key);
if(isset($this->$key)){
return $this->$key;
}
return '$this->'.$oldKey.' not exist';
}
}
$obj = new magic1();
echo $obj-> age; // 访问被private修饰的属性
echo '</br>';
echo $obj->height;//访问被protected修饰的属性
echo '</br>';
echo $obj->job; //访问不存在的属性
执行以上程序的运行结果为:
execute __get() method.string(5) "__age" 22 years old
execute __get() method.string(8) "__height" 170cm
execute __get() method.string(5) "__job" $this->job not exist
可见“excute __get() method”这个字符串被打印了3次,说明这3次都成功调用了__get()方法。在__get()方法里加入了3个判断,是因为在定义被private和protected修饰的属性时习惯在名称前加上一个或两个下划线,所以在类外部访问一个不存在的属性时可在__get()方法中确定要访问的是否为被加了下划线的非公开属性。
9.3.2 __isset()和__unset()方法
1. __isset()方法
当在类外部对未定义的属性或者非公有属性使用isset()函数时,魔术方法__isset()将会被调用。示例代码如下:
<?php
/*
* class magic1 演示__isset()方法
* 当在类外部对未定义的属性或者非公有属性使用isset()函数时,魔术方法__isset()将会被调用。
* */
class magic2{
public $father='chenxiaolong';
private $_name;
private $_age='22 years old';
protected $__height='170cm';
private $_hobby='basketball';
function __isset($key)
{
if(property_exists('magic2',$key)){
echo 'property'.$key.' exists</br>';
}else{
echo 'property'.$key.' not exists</br>';
}
}
}
$obj = new magic2();
isset($obj->_hobby); //被private修饰的属性
isset($obj->lover); //不存在的属性
isset($obj->father);//被public修饰的属性,不会触发__set()方法
isset($obj->__height);//被protected修饰的属性
程序输出
property_hobby exists
propertylover not exists
property__height exists
说明:property_exists()用来检测类中是否定义了该属性,用法为property_exists(class_name, property_name),即判断类class_name中是否定义了property_name属性。
2. __unset()方法
对类中未定义的属性或非公有属性进行unset()操作时,将会触发__unset()方法。如果属性存在,unset()操作会销毁这个属性,释放该属性在内存中占用的空间。再用对象访问这个属性时,将会返回NULL。
<?php
/*
* class magic1 演示__unset()方法
* 对类中未定义的属性或非公有属性进行unset()操作时,将会触发__unset()方法。
* */
class magic3{
public $father='chenxiaolong';
private $_name;
private $_age='22 years old';
protected $__height='170cm';
private $_hobby='basketball';
function __unset($key)
{
if(property_exists('magic3',$key)){
unset($this->$key);
echo 'property'.$key.' has been unseted</br>';
}else{
echo 'property'.$key.' not exists</br>';
}
}
}
$obj = new magic3();
unset($obj->_hobby);
unset($obj->lover);
unset($obj->father);// 存在该属性且被public修饰,不会触发__unset()方法
unset($obj->__height);
?>
程序输出
property_hobby has been unseted
propertylover not exists
property__height has been unseted
9.3.3 __call() 和__ toString() 方法
1. __call() 方法
<?php
/*
* class magic4 演示__call()方法
*当试图调用类中不存在的方法时会触发__call()方法。__call()方法有两个参数,即方法名和参数,参数以索引数组的形式存在。
* */
class magic4{
function __call($func,$param){
echo "$func method not exists<br/>";
var_dump($param);
}
}
$obj=new magic4();
$obj->register("param1",'param2','param3');
程序输出
register method not exists
array(3) { [0]=> string(6) "param1" [1]=> string(6) "param2" [2]=> string(6) "param3" }
2. __toString()方法
<?php
/*
* class magic5 演示__toString()()方法
* 当使用echo或print打印对象时会调用__toString()方法将对象转化为字符串。
* */
class magic5{
function __toString(){
return 'when you want to echo or print the object,__toString() will be called';
}
}
$obj=new magic5();
print $obj;