PHP 魔术方法介绍

魔术方法介绍

PHP 将所有以 __(两个下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以 __ 为前缀。
在命名自己的类方法时不能使用这些方法名,除非是想使用其魔术功能。具体查看 官方手册
那么有哪些魔术方法呢?

  1. __construct()
  2. __destruct()
  3. __call()
  4. __callStatic()
  5. __get()
  6. __set()
  7. __isset()
  8. __unset()
  9. __sleep()
  10. __wakeup()
  11. __toString()
  12. __invoke()
  13. __set_state()
  14. __clone()
  15. __debugInfo()

下面我们用例子来说明每个魔术方法的用法:

__construct()

类实例化时候调用,可以传递参数。

1
2
3
4
5
6
7
8
9
class Demo
{
public function __construct()
{
echo 'init...';
}
}

$demo = new Demo();

__destruct()

析构函数,在类引用销毁的时候调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Demo
{
public function __construct()
{
echo "init...\n";
}

public function __destruct()
{
echo "destruct\n";
}
}

$demo = new Demo();
echo "this is running\n";
$demo = null; // 这里销毁变量
echo "this is end\n";

__call()

调用类无法访问的方法时,会触发,也就是说当你的方法修饰符为 privateprotected ,外面调用此方法,也会触发 __call()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Demo
{
protected function show()
{
echo "show\n";
}

public function __call($method, $parameters)
{
echo "Call: {$method}\n";
print_r($parameters);
}
}
$demo = new Demo;
$demo->show(1, 2);
$demo->add(1, 2);

__callStatic()

调用类无法访问的静态方法时,会触发,也就是说当你的方法修饰符为 privateprotected ,外面调用此方法,也会触发 __callStatic()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Demo
{
protected static function add($a, $b)
{
return $a + $b;
}

public static function __callStatic($method, $parameters)
{
echo "call static method: {$method}\n";
print_r($parameters);
}
}

Demo::add(1, 2);
Demo::max(1, 2);

__get()

当获取不可访问的类属性时,会触发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Demo
{
private $id = 1;
protected $title = 'title';
public $content = 'content';

public function __get($name)
{
echo "{$name} not exists!\n";
}
}
$demo = new Demo;
$demo->id;
$demo->title;
echo $demo->content;

__set()

当设置不可访问的类属性时,会触发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Demo
{
private $id = 1;
protected $title = 'title';
public $content = 'content';

public function __set($name, $value)
{
echo "set {$name} value {$value}\n";
}
}
$demo = new Demo;
$demo->id = 100;
$demo->title = 'new title';
$demo->content = 'new content';

__isset()

当调用方法 isset 且类方法不可访问时,会触发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Demo
{
private $id = 1;
protected $title = 'title';
public $content = 'content';

public function __isset($name)
{
echo "isset {$name}\n";
}
}
var_dump(isset($demo->id));
var_dump(isset($demo->title));
var_dump(isset($demo->content));

__unset()

当调用方法 unset 且类方法不可访问时,会触发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Demo
{
private $id = 1;
protected $title = 'title';
public $content = 'content';

public function __unset($name)
{
echo "unset {$name}\n";
}
}

unset($demo->id);
unset($demo->title);
unset($demo->content);

__sleep()

serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。如果该方法未返回任何内容,则 NULL 被序列化,并产生一个 E_NOTICE 级别的错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Parent
{
protected $pid = 100;
}
class Demo extends Parent
{
private $id = 1;
protected $title = 'title';
public $content = 'content';

public function __sleep()
{
$this->title = 'new title';
return ['id', 'title', 'content'];
}
}
$demo = new Demo;
echo serialize($demo);

__wakeup()

unserialize() 会检查是否存在一个 wakeup() 方法。如果存在,则会先调用 wakeup 方法,预先准备对象需要的资源。
__wakeup() 经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。

__toString()

将类实例作为一个变量输出的时候,会触发调用,如果不存在 __toString(),将发出一条 E_RECOVERABLE_ERROR 级别的致命错误。

注意:不能在 __toString() 方法中抛出异常。这么做会导致致命错误。

1
2
3
4
5
6
7
8
9
10
11
12
class Demo
{
private $id = 1;
protected $title = 'title';
public $content = 'content';
public function __toString()
{
return "id:{$this->id}\t title:{$this->title}\t content:{$this->content}\n";
}
}
$demo = new Demo;
echo $demo;

__invoke()

当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。

注意:此特性只有在 PHP5.3 及以上版本有效

1
2
3
4
5
6
7
8
9
class Demo
{
public function __invoke()
{
echo "class call\n";
}
}
$demo = new Demo;
$demo();

__set_state()

自 PHP 5.1.0 起当调用 var_export() 导出类时,此静态 方法会被调用。
本方法的唯一参数是一个数组,其中包含按 array(‘property’ => value, …) 格式排列的类属性。
这个方法的例子 查看

__clone()

使用 clone 复制对象时,会被调用。

1
2
3
4
5
6
7
8
9
10
11
12
class Demo
{
public $id = 1;
public function __clone()
{
$this->id += 100;
}
}
$demo = new Demo;
print_r($demo);
$new = clone $demo;
print_r($new);

__debugInfo()

调用 var_dump 等打印函数时会触发,如果没有定义 __debugInfo,输出类对象,定义了执行。

注意:这个特性在 PHP 5.6.0 新增

1
2
3
4
5
6
7
8
9
10
11
12
class Demo
{
public function __debugInfo()
{
return [
'id' => $this->id,
'title' => $this->title
];
}
}
$demo = new Demo;
var_dump($demo);

©版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 & 作者信息

End

坚持原创技术分享,您的支持将鼓励我继续创作!
Flyertutor WeChat Pay

WeChat Pay

Flyertutor Alipay

Alipay