常见的魔术方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
__construct(),类的构造函数
__destruct(),类的析构函数
__call(),在对象中调用一个不可访问方法时调用
__callStatic(),用静态方式中调用一个不可访问方法时调用
__get(),获得一个类的成员变量时调用
__set(),设置一个类的成员变量时调用
__isset(),当对不可访问属性调用isset()或empty()时调用
__unset(),当对不可访问属性调用unset()时被调用
__sleep(),执行serialize()时,先会调用这个函数
__wakeup(),执行unserialize()时,先会调用这个函数
__toString(),类被当成字符串时的回应方法
__invoke(),调用函数的方式调用一个对象时的回应方法
__set_state(),调用var_export()导出类时,此静态方法会被调用
__clone(),当对象复制完成时调用
__autoload(),尝试加载未定义的类
__debugInfo(),打印所需调试信息

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
<?php
highlight_file(__FILE__);
echo "<br>";
class magic_test
{
public $data1="zIxyd";
public $data2="writeup";
public function print_dat()
{
echo $this->data1 . " " .$this->data2 . "<br>";
}
public function __construct()
{//构造函数
echo "__construct<br>";
}
public function __destruct()
{//析构函数
echo "__destruct<br>";
}
public function __wakeup()
{//执行unserialize时调用
echo "__wakeup<br>";
}
public function __sleep()
{//执行serialize时调用
echo "__sleep<br>";
return array("data1","data2");
//__sleep()该函数必须返回一个需要进行序列化保存的成员属性数组
//并且只序列化该函数返回的这些成员属性
}
public function __toString()
{//类被当成字符串时的回应方法
//echo "__toString<br>";
return "__toString<br>";
}
function __call($name, $arg)
{//在对象中调用一个不可访问方法时调用
//不存在的方法名是$name,参数是数组形式
echo "$name<br>";
var_dump($arg);
echo "<br>";
}
function __invoke()
{//调用函数的方式调用一个对象时的回应方法
echo "__invoke<br>";
}
function __get($key)
{//获得一个类中不可访问的成员变量时(未定义或私有属性)
echo "__get<br>";
}
function __set($arg1,$arg2)
{//给一个类中不可访问的成员变量赋值时
echo "__set<br>";
echo "$arg1:$arg2 <br>";
}
}
//创建对象,调用__construct
echo "准备创建对象<br>";
$obj = new magic_test();
echo "创建对象完成<br>";

//序列化对象,调用__sleep
echo "准备序列化对象<br>";
$serialized = serialize($obj);
echo "序列化对象完成<br>";

//类被当成字符串输出,调用__toString
echo "准备输出类<br>";
echo $obj;
echo "输出类完毕<br>";

//类被当成方法调用输出,调用__invoke
echo "准备把对象当作方法调用<br>";
$obj();
echo "把对象当作方法调用完毕<br>";

//输出序列化之后的字符串
echo "打印序列化之后的对象 ";
echo "serialized: ".$serialized."<br>";
echo "打印完成<br>";

//调用一个不存在的方法,调用__call
echo "准备调用不存在的方法hack<br>";
$obj->hack('arg1','arg2',3);
echo "调用不存在的方法hack完毕<br>";

//获得一个类不存在的成员变量时,调用__get
echo "准备访问对象不存在的字段<br>";
$function = $obj->nono;
echo "访问对象不存在的字段完毕<br>";

//获得一个类不存在的成员变量时,调用__set
echo "准备设置对象不存在的字段<br>";
$obj->onon = 123;
echo "设置对象不存在的字段完毕<br>";

//重建对象(反序列化),调用__wakeup
echo "准备反序列化对象<br>";
$obj2=unserialize($serialized);
echo "反序列化完成<br>";

//调用方法
echo "准备调用方法<br>";
$obj2->print_dat();
echo "调用结束<br>";

//反序列化后会额外在调用__destruct
//脚本结束 调用__destruct
?>