本文最后更新于:2024年12月14日 下午
__construct() , __destruct() , __call() , __callStatic() , __get() , __set() , __isset() , __unset() , __sleep() , __wakeup() , __serialize() , __unserialize() , __toString() , __invoke() , __set_state() , __clone() 和 __debugInfo() 等方法在 PHP 中被称为魔术方法(Magic methods)
所有的魔术方法都要以public来声明.
__construct()
和__destruct()
__construct()
是构造方法,即创建一个对象的时候,首先干的事情。
官方文档的说法是:PHP 允许开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。
1 2 3 4 5 6 7 8 9 10 11 12 class test { public $filename = '' ; public $data = '' ; function __construct ($filename , $data ) { $this ->filename = $filename ; $this ->data = $data ; echo 'construct function in test class' ; echo "<br>" ; } }$a = new test ('test.txt' , 'data' );
例如以上代码的执行结果就是construct function in test class
__destruct()
即析构函数,析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。
官方文档给出了一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php class MyDestructableClass { function __construct ( ) { print "In constructor\n" ; } function __destruct ( ) { print "Destroying " . __CLASS__ . "\n" ; } }$obj = new MyDestructableClass ();
这段代码的运行结果是这样的:
我的理解就是这个对象所有内容执行完后所运行的代码。
__set()
,__get()
,__isset()
,__unset()
以下是官方文档的说法:
PHP所提供的重载(overloading)是指动态地创建类属性和方法。我们是通过魔术方法(magic methods)来实现的。
当调用当前环境下未定义或不可见的类属性或方法时,重载方法会被调用。本节后面将使用不可访问属性(inaccessible properties)和不可访问方法(inaccessible methods)来称呼这些未定义或不可见的类属性或方法。
所有的重载方法都必须被声明为 public
。
同样,也给出了这四个方法的用例
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 <?php class PropertyTest { private $data = array (); public $declared = 1 ; private $hidden = 2 ; public function __set ($name , $value ) { echo "Setting '$name ' to '$value '\n" ; $this ->data[$name ] = $value ; } public function __get ($name ) { echo "Getting '$name '\n" ; if (array_key_exists ($name , $this ->data)) { return $this ->data[$name ]; } $trace = debug_backtrace (); trigger_error ( 'Undefined property via __get(): ' . $name . ' in ' . $trace [0 ]['file' ] . ' on line ' . $trace [0 ]['line' ], E_USER_NOTICE); return null ; } public function __isset ($name ) { echo "Is '$name ' set?\n" ; return isset ($this ->data[$name ]); } public function __unset ($name ) { echo "Unsetting '$name '\n" ; unset ($this ->data[$name ]); } public function getHidden ( ) { return $this ->hidden; } }echo "<pre>\n" ;$obj = new PropertyTest ;$obj ->a = 1 ;echo $obj ->a . "\n\n" ;var_dump (isset ($obj ->a));unset ($obj ->a);var_dump (isset ($obj ->a));echo "\n" ;echo $obj ->declared . "\n\n" ;echo "Let's experiment with the private property named 'hidden':\n" ;echo "Privates are visible inside the class, so __get() not used...\n" ;echo $obj ->getHidden () . "\n" ;echo "Privates not visible outside of class, so __get() is used...\n" ;echo $obj ->hidden . "\n" ;?>
我用自己的理解给他注释了一下
全部的运行结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Setting 'a ' to '1' Getting 'a '1 Is 'a ' set? bool(true ) Unsetting 'a 'Is 'a ' set? bool(false )1 Let's experiment with the private property named 'hidden ': Privates are visible inside the class, so __get() not used...2 Privates not visible outside of class, so __get() is used... Getting 'hidden ' Notice: Undefined property via __get(): hidden in <file > on line 70 in <file > on line 29
到这里其实基本已经明晰了,这里的魔术方法其实有点类似于python中的装饰器,定义在访问这个方法的同时额外执行任务的代码(纯属个人理解哈)
__call()
和__callstatic()
这俩其实也属于重载一类,老规矩先看文档的介绍:
同样的官网也给出了一个简单的例子,我们来复现一下:
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 <?php class MethodTest { public function __call ($name , $arguments ) { echo "Calling object method '$name ' " . implode (', ' , $arguments ). "\n" ; } public static function __callStatic ($name , $arguments ) { echo "Calling static method '$name ' " . implode (', ' , $arguments ). "\n" ; } }$obj = new MethodTest ;$obj ->runTest ('in object context' );MethodTest ::runTest ('in static context' );?>
虽然代码很简短,我还是趁热打铁注释一下吧。(运行结果已经注释进去)
静态方法有点陌生:
静态方法其实就是不需要对象即可调用的方法
__sleep()
,__wakeup()
这2个方法在php反序列化中非常常见。
文档的介绍如上
由于文档这里给出的演示代码个人感觉不是很清晰,所以这里借鉴了博主Magic_Zero 的演示代码
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 class test { private $flag = '' ; private $data = array (); public $filename = '' ; public $content = '' ; function __construct ($filename , $content ) { $this ->filename = $filename ; $this ->content = $content ; echo 'construct function in test class' ; echo "<br>" ; } function __destruct ( ) { echo 'destruct function in test class' ; echo "<br>" ; } function __wakeup ( ) { echo 'wakeup function in test class' ; echo "<br>" ; } function __sleep ( ) { echo 'sleep function in test class' ; echo "<br>" ; return array ('flag' , 'filename' , 'data' ); } function __toString ( ) { return $this ->data; } public function set_flag ($flag ) { $this ->flag = $flag ; } public function get_flag ( ) { return $this ->flag; } }$key = serialize (new test ('test.txt' , 'test' ));var_dump ($key );$b = unserialize ($key );
由于这位大佬写的非常清晰了就不再注释了
var_dump() 函数显示关于一个或多个表达式的结构信息,包括表达式的类型与值。数组将递归展开值,通过缩进显示其结构。
__tostring()
__toString() 方法用于一个类被当成字符串时应怎样回应。例如 echo $obj;
应该显示些什么。此方法必须返回一个字符串,否则将发出一条 E_RECOVERABLE_ERROR
级别的致命错误。
直接看文档上的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?php class TestClass { public $foo ; public function __construct ($foo ) { $this ->foo = $foo ; } public function __toString ( ) { return $this ->foo; } }$class = new TestClass ('Hello' );echo $class ;?>
注释了一下
输出结果是Hello
至此本文结束
参考文献:
https://www.cnblogs.com/magic-zero/p/7360396.html
https://www.php.net/manual/zh/language.oop5.magic.php#object.tostring