• PHP中的魔术方法,指的一般是:以双下划线开头,不需要显示的调用,在特定的条件下,会被自动调用的方法。
  • 这里记录了目前为止所有的 魔术方法,一共15个
    • 这些魔术方法,几乎都是为了类的实例服务的,这么规定给我们留下了很大的操作空间
    • 由于会被自动调用,所以规定的访问权限一般都是 public
    • 针对于 属性
      • __get():访问不可访问的属性会被自动调用
      • __set():设置不可设置的属性会被自动调用
      • __isset():试图通过 empty()、isset() 来访问不可访问的属性时会被自动调用
      • __unset() :试图在外部通过unset()方法,来删除对象的某一个属性时会被自动调用
    • 序列化和反序列化
      • __sleep():序列化自动调用
      • __wakeup():反序列化自动调用
    • 构造和析构
      • __construct():创建对象自动调用
      • __destruct():销毁对象时自动调用
    • 调试输出对象
      • __set_state():var_export() 时自动调用
      • __debuginfo():var_dump() 时自动调用
    • 打印对象
      • __toString():将对象当字符串使用时自动调用
    • 克隆对象
      • __clone():克隆对象时自动调用
    • 访问方法
      • __call():访问无法访问的非静态方法是自动调用
      • __callStatic():访问无法访问的静态方法时调用
    • 将对象当成方法时调用
      • __invoke():就这个方法不像是其它方法一样成对出现

PHP中所有的魔术方法

1. __construct()

创建对象时调用。构造方法,创建一个类实例自动调用它的构造函数来完成创建,PHP中的构造函数逼向Java不是类名,而是 __construct().

  1. <?php
  2. class Person
  3. {
  4. private $name;
  5. private $gender;
  6. private $age;
  7. public function __construct($name, $gender, $age)
  8. {
  9. $this->name = $name;
  10. $this->gender = $gender;
  11. $this->age = $age;
  12. }
  13. }
  14. var_dump(new Person('xs', 'male', 24));
  15. /*
  16. object(Person)#1 (3) {
  17. ["name":"Person":private]=>
  18. string(2) "xs"
  19. ["gender":"Person":private]=>
  20. string(4) "male"
  21. ["age":"Person":private]=>
  22. int(24)
  23. }
  24. */

2. __destruct()

销毁对象时被自动调用,一般来说,我们并不用去特别设置这个函数。

  1. <?php
  2. class Person
  3. {
  4. private $name;
  5. private $gender;
  6. private $age;
  7. public function __construct($name, $gender, $age)
  8. {
  9. $this->name = $name;
  10. $this->gender = $gender;
  11. $this->age = $age;
  12. }
  13. public function __destruct()
  14. {
  15. print '对象被销毁了!';
  16. }
  17. }
  18. $p1 = new Person('xs', 'male', 24);
  19. unset($p1); // 对象被销毁了!

3. __call()

当访问不存在的非静态方法时被自动调用,这个方法接受两个参数,第一个参数是方法的名称,第二参数是一个数组用于保存形参

  1. <?php
  2. class Person
  3. {
  4. private $name;
  5. private $gender;
  6. private $age;
  7. public function __construct($name, $gender, $age)
  8. {
  9. $this->name = $name;
  10. $this->gender = $gender;
  11. $this->age = $age;
  12. }
  13. public function __call($name, $arguments)
  14. {
  15. echo '__call is called ' . "\r";
  16. echo 'Method Name :' . $name . "\r" . 'Args :' . implode(',', $arguments);
  17. }
  18. public static function __callStatic($name, $arguments)
  19. {
  20. echo '__callStatic is called ' . "\r";
  21. echo 'Method Name :' . $name . "\r" . 'Args :' . implode(',', $arguments);
  22. }
  23. }
  24. $p1 = new Person('xs', 'male', 24);
  25. $p1->go(1, 2, 3, 4);
  26. /*
  27. __call is called
  28. Method Name :go
  29. Args :1,2,3,4
  30. */

4. __callStatic()

和__call()类似,当访问不存在静态的方法时会被自动调用

  1. <?php
  2. class Person
  3. {
  4. private $name;
  5. private $gender;
  6. private $age;
  7. public function __construct($name, $gender, $age)
  8. {
  9. $this->name = $name;
  10. $this->gender = $gender;
  11. $this->age = $age;
  12. }
  13. public function __call($name, $arguments)
  14. {
  15. echo '__call is called ' . "\r";
  16. echo 'Method Name :' . $name . "\r" . 'Args :' . implode(',', $arguments);
  17. }
  18. public static function __callStatic($name, $arguments)
  19. {
  20. echo '__callStatic is called ' . "\r";
  21. echo 'Method Name :' . $name . "\r" . 'Args :' . implode(',', $arguments);
  22. }
  23. }
  24. $p1 = new Person('xs', 'male', 24);
  25. $p1::go(1, 2, 3, 4);
  26. /*
  27. __callStatic is called
  28. Method Name :go
  29. Args :1,2,3,4
  30. */

5. __get()

当试图访问获取不到的属性时,会被自动调用,这个方法只有一个参数这个参数是访问的属性名称。

  1. <?php
  2. class Person
  3. {
  4. private $name;
  5. private $gender;
  6. private $age;
  7. public function __construct($name, $gender, $age)
  8. {
  9. $this->name = $name;
  10. $this->gender = $gender;
  11. $this->age = $age;
  12. }
  13. public function __get($name)
  14. {
  15. echo '访问的属性无法直接获取' . " $name \r";
  16. }
  17. }
  18. $p1 = new Person('xs', 'male', 24);
  19. // 1. 比如这里我们访问一个私有的属性
  20. $p1->age; // 访问的属性无法直接获取 age
  21. // 2. 访问一个不存在的属性
  22. $p1->go; // 访问的属性无法直接获取 go

6. __set()

当设置私有的属性或者是其他不存在的属性,总之设置当前无法设置的属性时该方法会被自动调用。接收两个参数,第一个参数是被设置的属性,第二个参数是被设置属性的值。

  1. <?php
  2. class Person
  3. {
  4. private $name;
  5. private $gender;
  6. private $age;
  7. public function __construct($name, $gender, $age)
  8. {
  9. $this->name = $name;
  10. $this->gender = $gender;
  11. $this->age = $age;
  12. }
  13. public function __set($name, $value)
  14. {
  15. echo "无法设置 $name 为 $value \r";
  16. }
  17. }
  18. $p1 = new Person('xs', 'male', 24);
  19. $p1->age = 10; // 无法设置 age 为 10
  20. $p1->go = 10; // 无法设置 go 为 10

7. __isset()

当试图通过 isset() 或者 empty() 来访问不可访问的属性时调用该方法

  1. <?php
  2. class Person
  3. {
  4. private $name;
  5. private $gender;
  6. private $age;
  7. public function __construct($name, $gender, $age)
  8. {
  9. $this->name = $name;
  10. $this->gender = $gender;
  11. $this->age = $age;
  12. }
  13. public function __isset($name)
  14. {
  15. echo "无法通过isset($name) 或者 empty($name) 访问属性$name \r";
  16. }
  17. }
  18. $p1 = new Person('xs', 'male', 24);
  19. isset($p1->age); // 无法通过isset(age) 或者 empty(age) 访问属性age
  20. empty($p1->age); // 无法通过isset(age) 或者 empty(age) 访问属性age

8. __unset()

在对象里面加上了”unset()”这个方法之后,在对象外部使用”unset()”函数删除对象内部的私有成员属性时,自动调用”unset()”函数来帮我们删除对象内部的私有成员属性,这个方法也可以在类的内部定义成私有的。在对象里面加上下面的代码就可以了:

  1. <?php
  2. class Person
  3. {
  4. private $name;
  5. private $gender;
  6. private $age;
  7. public function __construct($name, $gender, $age)
  8. {
  9. $this->name = $name;
  10. $this->gender = $gender;
  11. $this->age = $age;
  12. }
  13. private function __unset($name)
  14. {
  15. echo "调用了 unset($name) 删除一个类属性 \r";
  16. unset($this->$name);
  17. }
  18. }
  19. // 删除某个实例的属性
  20. $p1 = new Person('xs', 'male', 24);
  21. unset($p1->age);
  22. var_dump($p1);
  23. /*
  24. 调用了 unset(age) 删除一个类属性
  25. object(Person)#1 (2) {
  26. ["name":"Person":private]=>
  27. string(2) "xs"
  28. ["gender":"Person":private]=>
  29. string(4) "male"
  30. }
  31. */

9. __sleep()

在类外部使用serialize()时自动调用

  1. <?php
  2. class Person
  3. {
  4. private $name;
  5. private $gender;
  6. private $age;
  7. public function __construct($name, $gender, $age)
  8. {
  9. $this->name = $name;
  10. $this->gender = $gender;
  11. $this->age = $age;
  12. }
  13. public function __sleep()
  14. {
  15. echo "当在类外部使用serialize()时会调用这里的__sleep()方法 \r";
  16. $this->name = base64_encode($this->name);
  17. $this->gender = base64_encode($this->gender);
  18. $this->age = base64_encode($this->age);
  19. // 这里必须返回一个数值,里边的元素表示返回的属性名称
  20. return array('name', 'gender', 'age');
  21. }
  22. }
  23. $person = new Person('向上', '男', 24); // 初始赋值
  24. $ser = serialize($person);
  25. echo $ser; // O:6:"Person":3:{s:12:"

10. __wakeup()

反序列化的时候调用

  1. <?php
  2. // ... ....

11. __toString()

直接输出对象引用时自动调用的方法,简单来说就是,对象被当成字符串使用的使用。我们都知道,PHP中是不可以直接 echo $instance,如果我们自己定义并按照个人的需求去类中添加 “__toString()”,就可以了。

  1. <?php
  2. class Person
  3. {
  4. private $name;
  5. private $gender;
  6. private $age;
  7. public function __construct($name, $gender, $age)
  8. {
  9. $this->name = $name;
  10. $this->gender = $gender;
  11. $this->age = $age;
  12. }
  13. public function __toString()
  14. {
  15. return
  16. 'name :' . $this->name . '\r' .
  17. 'gender :' . $this->gender . '\r' .
  18. 'age :' . $this->age ;
  19. }
  20. }
  21. echo (new Person('xs', 'male', 24)); // name :xs\rgender :male\rage :24

12. __invoke()

当对象被当成函数去使用的时候会被自动调用

  1. <?php
  2. class Person
  3. {
  4. private $name;
  5. private $gender;
  6. private $age;
  7. public function __construct($name, $gender, $age)
  8. {
  9. $this->name = $name;
  10. $this->gender = $gender;
  11. $this->age = $age;
  12. }
  13. public function __invoke()
  14. {
  15. echo '__invoked() is called';
  16. }
  17. }
  18. $p1 = new Person('xs', 'male', 24);
  19. $p1(); // __invoked() is called

13. __set_state()

当调用 var_export() 导出类时,此静态方法会被自动调用. 就是var_export()的回调函数

先不添加这个方法,我们使用 var_export**

  1. <?php
  2. class Person
  3. {
  4. private $name;
  5. private $gender;
  6. private $age;
  7. public function __construct($name, $gender, $age)
  8. {
  9. $this->name = $name;
  10. $this->gender = $gender;
  11. $this->age = $age;
  12. }
  13. }
  14. var_export(new Person('向上', '男', 24));
  15. /*
  16. Person::__set_state(array(
  17. 'name' => '向上',
  18. 'gender' => '男',
  19. 'age' => 24,
  20. ))
  21. */

添加这个方法


14. __clone()

克隆对象时被自动调用

  1. <?php
  2. class Person
  3. {
  4. private $name;
  5. private $gender;
  6. private $age;
  7. public function __construct($name, $gender, $age)
  8. {
  9. $this->name = $name;
  10. $this->gender = $gender;
  11. $this->age = $age;
  12. }
  13. public function __clone()
  14. {
  15. echo 'who clone me';
  16. }
  17. }
  18. $p1 = new Person('xs', 'male', 24);
  19. $p2 = clone $p1; // who clone me

15. __debuglnfo()

该方法在var_dump()类对象的时候被调用,如果没有定义该方法,则var_dump会打印出所有的类属性,5.6以上的版本

  1. <?php
  2. class Person
  3. {
  4. public $name;
  5. public $gender;
  6. public $age;
  7. public function __construct($name, $gender, $age)
  8. {
  9. $this->name = $name;
  10. $this->gender = $gender;
  11. $this->age = $age;
  12. }
  13. public function __debugInfo()
  14. {
  15. return [
  16. 'name' => $this->name,
  17. 'age' => $this->age,
  18. 'gender' => $this->gender
  19. ];
  20. }
  21. }
  22. var_dump(new Person('xs', '男', 24));