魔术方法是一种特殊的方法,当对对象执行某些操作时会覆盖 PHP 的默认操作。
魔术方法
PHP
将所有以 __
(两个下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了心下魔术方法,建议不要以 __
为前缀。
名称 | 说明 | 备注 |
---|
__construct() | 类的构造函数 | |
__destruct() | 类的析构函数 | |
__call() | 在对象中调用一个不可访问方法时调用 | |
__callStatic() | 用静态方式中调用一个不可访问方法时调用 | |
__get() | 获得一个类的成员变量时调用 | |
__set() | 设置一个类的成员变量时调用 | |
__isset() | 当对不可访问属性调用 isset() 或 empty() 时调用 | |
__unset() | 当对不可访问属性调用 unset() 时被调用 | |
__sleep() | 执行 serialize() 时,先会调用这个函数 | |
__wakeup() | 执行 unserialize() 时,先会调用这个函数 | |
__toString() | 用于一个类被当成字符串时应怎样回应 | |
__invoke() | 当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用 | |
__set_state() | 调用 var_export() 导出类时,此静态方法会被调用 | |
__clone() | 当复制完成时,如果定义了 __clone() 方法,则新创建的对象(复制生成的对象)中的 __clone() 方法会被调用,可用于修改属性的值(如果有必要的话) | |
__debugInfo() | 当打印一个对象以获取显示的属性时,此方法被 var_dump() 调用。如果此方法未在对象上定义,则将显示所有公开的,受保护的和私有的属性 | |
方法实例
__construct()
和 __destruct()
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
| <?php
class Object
{
public function __construct()
{
echo __METHOD__ . PHP_EOL;
}
public function __destruct()
{
echo __METHOD__ . PHP_EOL;
}
}
class Test extends Object
{
public function __construct()
{
echo __METHOD__ . PHP_EOL;
parent::__construct();
}
public function __destruct()
{
echo __METHOD__ . PHP_EOL;
parent::__destruct();
}
}
new Test();
// 结果
Test::__construct
Object::__construct
Test::__destruct
Object::__destruct
|
__call()
和 __callStatic()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| <?php
class Object
{
public function __call($name, $arguments)
{
echo "Calling object method '$name' " . implode(', ', $arguments) . PHP_EOL;
}
public static function __callStatic($name, $arguments)
{
echo "Calling static method '$name' " . implode(', ', $arguments) . PHP_EOL;
}
}
$object = new Object();
$object->getCall('in object context');
Object::getCallStatic('in static context');
// 结果
Calling object method 'getCall' in object context
Calling static method 'getCallStatic' in static context
|
__get()
, __set()
, __isset()
, __unset()
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
| <?php
class Object
{
private $data = [];
public function __set($key, $val)
{
echo __METHOD__ . PHP_EOL;
$this->data[$key] = $val;
}
public function __get($key)
{
if (array_key_exists($key, $this->data)) {
echo __METHOD__ . PHP_EOL;
return $this->data[$key];
}
return null;
}
public function __isset($key)
{
echo __METHOD__ . PHP_EOL;
return isset($this->data[$key]);
}
public function __unset($key)
{
echo __METHOD__ . PHP_EOL;
unset($this->data[$key]);
}
}
$object = new Object();
$object->property = 'This is the property of the object.';
$object->property;
isset($object->property);
unset($object->property);
// 结果
Object::__set
Object::__get
Object::__isset
Object::__unset
|
__sleep()
和 __wakeup
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
| <?php
class Object
{
protected $link;
private $server, $username, $password, $database;
public function __construct($server, $username, $password, $database)
{
echo __METHOD__ . PHP_EOL;
$this->server = $server;
$this->username = $username;
$this->password = $password;
$this->database = $database;
}
public function __sleep()
{
echo __METHOD__ . PHP_EOL;
return ['server', 'username', 'password', 'database'];
}
public function __wakeup()
{
echo __METHOD__ . PHP_EOL;
$this->connect();
}
private function connect()
{
echo __METHOD__ . PHP_EOL;
$this->link = mysqli_connect(
$this->server,
$this->username,
$this->password
);
}
}
$object = new Object('localhost', 'root', '', 'test');
$serialize = serialize($object);
unserialize($serialize);
// 结果
Object::__construct
Object::__sleep
Object::__wakeup
Object::connect
|
__toString()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| <?php
class Object
{
public function __toString()
{
return __METHOD__;
}
}
$object = new Object();
echo $object;
// 结果
Object::__toString
|
__invoke()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| <?php
class Object
{
public function __invoke()
{
echo __METHOD__ . PHP_EOL;
}
}
$object = new Object();
var_dump(is_callable($object()));
// 结果
Object::__invoke
bool(false)
|
__set_state()
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
| <?php
class Object
{
public $a;
public $b;
public static function __set_state(array $array)
{
echo __METHOD__ . PHP_EOL;
$object = new Object();
$object->a = $array['a'];
$object->b = $array['b'];
return $object;
}
}
$object = new Object();
$object->a = 'this is a';
$object->b = 'this is b';
eval('$b = ' . var_export($object, true) . ';');
var_dump($b);
// 结果
Object::__set_state
object(Object)#2 (2) {
["a"]=>
string(9) "this is a"
["b"]=>
string(9) "this is b"
}
|
__clone()
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
| <?php
class Object
{
public static $count = 0;
public $instance;
public function __construct()
{
echo __METHOD__ . PHP_EOL;
$this->instance = ++self::$count;
}
public function __clone()
{
echo __METHOD__ . PHP_EOL;
$this->instance = ++self::$count;
}
}
class Cloneable
{
public $object1;
public $object2;
public function __construct()
{
echo __METHOD__ . PHP_EOL;
}
public function __clone()
{
echo __METHOD__ . PHP_EOL;
// 强制复制一份 this->object,否则仍然指向同一个对象
$this->object1 = clone $this->object1;
}
}
$cloneable = new Cloneable();
$cloneable->object1 = new Object();
$cloneable->object2 = new Object();
$clone = clone $cloneable;
print "Original Object:\n";
var_dump($cloneable);
print "Cloned Object:\n";
var_dump($clone);
// 结果
Cloneable::__construct
Object::__construct
Object::__construct
Cloneable::__clone
Object::__clone
Original Object:
class Cloneable#1 (2) {
public $object1 =>
class Object#2 (1) {
public $instance =>
int(1)
}
public $object2 =>
class Object#3 (1) {
public $instance =>
int(2)
}
}
Cloned Object:
class Cloneable#4 (2) {
public $object1 =>
class Object#5 (1) {
public $instance =>
int(3)
}
public $object2 =>
class Object#3 (1) {
public $instance =>
int(2)
}
}
|
__debugInfo()
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
| <?php
date_default_timezone_set('PRC');
class Object
{
public $year, $month, $day, $hour, $minute, $second;
public function __debugInfo()
{
$date = $this->year . '-' . $this->month . '-' . $this->day;
$time = $this->hour . ':' . $this->minute . ':' . $this->second;
$datetime = $date . ' ' . $time;
return [
'date' => $date,
'time' => $time,
'datetime' => $datetime,
'property' => call_user_func('get_object_vars', $this),
];
}
}
$object = new Object();
$object->year = date('Y');
$object->month = date('m');
$object->day = date('d');
$object->hour = date('H');
$object->minute = date('i');
$object->second = date('s');
var_dump($object);
// 结果
class Object#1 (4) {
public $date =>
string(10) "2018-01-18"
public $time =>
string(8) "17:27:45"
public $datetime =>
string(19) "2018-01-18 17:27:45"
public $property =>
array(6) {
'year' =>
string(4) "2018"
'month' =>
string(2) "01"
'day' =>
string(2) "18"
'hour' =>
string(2) "17"
'minute' =>
string(2) "27"
'second' =>
string(2) "45"
}
}
|
魔术常量
名称 | 说明 | 备注 |
---|
__LINE__ | 文件中的当前行号 | |
__FILE__ | 文件的完整路径和文件名 | |
__DIR__ | 文件所在的目录 | |
__FUNCTION__ | 函数名称 | |
__CLASS__ | 类的名称 | |
__TRAIT__ | Trait 的名字 | |
__METHOD__ | 类的方法名 | |
__NAMESPACE__ | 当前命名空间的名称 | |
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
| <?php
namespace App;
trait ObjectTrait
{
public function getTrait()
{
echo __TRAIT__ . PHP_EOL;
}
}
class Object
{
use ObjectTrait;
public function __construct()
{
echo __LINE__ . PHP_EOL;
echo __FILE__ . PHP_EOL;
echo __DIR__ . PHP_EOL;
echo __FUNCTION__ . PHP_EOL;
echo __CLASS__ . PHP_EOL;
echo $this->getTrait();
echo __METHOD__ . PHP_EOL;
}
}
$object = new Object();
// 结果
19
/Users/xxx/Downloads/test/vscode.php
/Users/xxx/Downloads/test
__construct
App\Object
App\ObjectTrait
App\Object::__construct
|