目录

PHP 魔术方法

魔术方法是一种特殊的方法,当对对象执行某些操作时会覆盖 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