前言
__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __serialize(), __unserialize(), __toString(), __invoke(), __set_state(), __clone() 和 __debugInfo() 等方法在 PHP 中被称为魔术方法(Magic methods)。在命名自己的类方法时不能使用这些方法名,除非是想使用其魔术功能。
参考文献
魔术方法官方文档:https://www.php.net/manual/zh/language.oop5.magic.php
演示
__construct:构造方法
__destruct:析构函数
<?php
class Magic
{
// 构造函数
public function __construct() {
echo '对象被实例化 new 的时候调用此方法' . PHP_EOL;
}
// 析构函数
public function __destruct() {
echo '对象删除或者销毁时被调用' . PHP_EOL;
}
}
new Magic;
/*输出:
对象被实例化 new 的时候调用此方法 对
象删除或者销毁时被调用
*/
__call(),在对象中调用一个不可访问方法时调用
__callStatic(),用静态方式中调用一个不可访问方法时调用
<?php
class Magic {
public function __call($funName, $arguments) {
echo "你所调用的函数:" . $funName . "(参数:"; // 输出调用不存在的方法名
print_r($arguments); // 输出调用不存在的方法时的参数列表
echo ")不存在!\n" . PHP_EOL; // 结束换行
}
// 声明此方法用来处理调用对象中不存在的方法
public static function __callStatic($funName, $arguments) {
echo "你所调用的静态方法:" . $funName . "(参数:"; // 输出调用不存在的方法名
print_r($arguments); // 输出调用不存在的方法时的参数列表
echo ")不存在!\n" . PHP_EOL; // 结束换行
}
}
$magic = new Magic;
var_dump($magic->testCall('names'));
var_dump(Magic::testCall('names'));
/*
输出:
你所调用的函数:testCall(参数:Array ( [0] => names ) )不存在!
NULL
你所调用的静态方法:testCall(参数:Array ( [0] => names ) )不存在!
NULL
*/
__get(),获得一个类的成员私有的变量时调用
<?php
class Magic {
// 私有变量
private $value = 100;
// 读取不可访问属性的值时调用
public function __get($propertyName) {
return $this->$propertyName = 200;
}
}
$magic = new Magic;
echo $magic->value;
/*输出:
200
*/
__set(),设置一个类的成员私有的变量时调用
<?php
class Magic {
// 私有变量
private $value = 100;
// 设置一个类的成员变量时调用
public function __set($property, $value){
$this->$property = $value;
}
// 输出私有方法
public function run(){
return $this->value;
}
}
$magic = new Magic;
$magic->value = 666;
echo $magic->run();
/*输出:
666
*/
__isset(),当对不可访问属性调用isset()或empty()时调用
__unset(),当对不可访问属性调用unset()时被调用
<?php
class Magic {
public $name = '张三';
private $area = '北京';
// 当对不可访问属性调用isset()或empty()时调用
public function __isset($content) {
echo "当在类外部使用isset()函数测定私有成员{$content}时,自动调用<br>";
echo isset($this->$content) . "<br>";
}
// 当对不可访问属性调用时被调用
public function __unset($content) {
echo "当在类外部使用unset()函数来删除私有成员时自动调用的<br>";
echo isset($this->$content) . "<br>";
}
}
$magic = new Magic;
echo isset($magic->name), "<br>"; // 返回:1
echo isset($magic->area), "<br>";
/*输出:
1
当在类外部使用isset()函数测定私有成员sex时,自动调用
1
*/
unset($magic->name); // 返回:1
unset($magic->area);
/*输出:
当在类外部使用unset()函数来删除私有成员时自动调用的
1
*/
__sleep(),执行serialize()时,先会调用这个函数
__wakeup(),执行unserialize()时,先会调用这个函数
<?php
class Magic {
public $name = '张三';
private $area = '北京';
public function __sleep(){
echo "当在类外部使用serialize()时会调用这里的__sleep()方法<br>";
$this->name = base64_encode($this->name);
return array('name', 'age'); // 这里必须返回一个数值,里边的元素表示返回的属性名称
}
public function __wakeup(){
echo "当在类外部使用unserialize()时会调用这里的__wakeup()方法<br>";
$this->name = '李四';
$this->area = '上海';
}
}
$magic = new Magic;
var_dump(serialize($magic));
/*输出:
当在类外部使用serialize()时会调用这里的__sleep()方法
O:5:"Magic":2:{s:4:"name";s:8:"5byg5LiJ";s:3:"age";N;}
*/
var_dump(unserialize(serialize($magic)));
/*输出:
当在类外部使用serialize()时会调用这里的__sleep()方法
当在类外部使用unserialize()时会调用这里的__wakeup()方法
object(Magic)#2 (3) { ["name"]=> string(6) "李四" ["area":"Magic":private]=> string(6) "上海" ["age"]=> NULL }
*/
__toString(),类被当成字符串时的回应方法
<?php
class Magic{
public function __toString(){
return '我是类呀,不是字符串';
}
}
$magic = new Magic;
echo $magic;
/*输出:
我是类呀,不是字符串
*/
__invoke(),调用函数的方式调用一个对象时的回应方法
<?php
class Magic{
public function __invoke(){
echo '这可是一个对象哦';
}
}
$magic = new Magic;
$magic();
/*输出:
这可是一个对象哦
*/
__set_state(),调用var_export()导出类时,此静态方法会被调用
<?php
class Magic{
public $name;
public $age;
public function __construct($name = "", $age = 25){
$this->name = $name;
$this->age = $age;
}
public static function __set_state($an_array){
$a = new Magic();
$a->name = $an_array['name'];
return $a;
}
}
$person = new magic('小明'); // 初始赋值
$person->name = '小红';
var_export($person);
/*输出:
Magic::__set_state(array( 'name' => '小红', 'age' => 25, ))
*/
__clone(),当对象复制完成时调用
<?php
class Magic{
public $name = '张三';
public function __clone() {
echo __METHOD__ . "你正在克隆对象<br>";
}
}
$magic = new magic();
$magic2 = clone $magic;
$magic->name = '李四';
echo $magic->name . "<br>"; // 李四
echo $magic2->name . "<br>"; // 张三
$magic2->name = '王五';
echo $magic->name . "<br>"; // 李四
echo $magic2->name . "<br>"; // 王五
/*输出:
Magic::__clone你正在克隆对象
李四
张三
李四
王五
*/
__autoload(),尝试加载未定义的类
警告 本函数已自
PHP 7.2.0
起被废弃,并自PHP 8.0.0
起被移除。 强烈建议不要依赖本函数。spl_autoload_register
— 注册给定的函数作为__autoload
的实现
<?php
function __autoload($className)
{
$filePath = "project/class/{$className}.php";
die($filePath);
if (is_readable($filePath)) {
require($filePath);
}
}
$a = new TestClass();
/*返回:
Deprecated: __autoload() is deprecated, use spl_autoload_register() instead in F:\www\aaa.php on line 2
project/class/TestClass.php
*/
__debugInfo(),打印所需调试信息
<?php
class Magic{
private $prop;
public function __construct($val){
$this->prop = $val;
}
public function __debugInfo(){
return [
'propSquared' => $this->prop ** 2, // 这里的 `**` 是乘方的意思
];
}
}
var_dump(new Magic(666));
/*输出:
object(Magic)#1 (1) { ["propSquared"]=> int(443556) }
*/