一、介绍
PHP魔术方法是以双下划线__开头的一组特殊方法,用于在对象生命周期、属性访问、方法调用等场景中实现自动化操作。简化面向对象编程。
二、17个现有的魔术方法
(一)、对象生命周期相关
1、__construct()
类的构造函数方法,具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。
2、__destruct()
类的析构函数,会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。
3、__get()
读取不可访问(protected 或 private)或不存在的属性的值时,__get() 会被调用。
4、__set()
在给不可访问(protected 或 private)或不存在的属性赋值时,__set() 会被调用。
5、__isset()
对不可访问(protected 或 private)或不存在的属性调用 isset() 或 empty() 时,__isset() 会被调用。
6、__unset()
当对不可访问(protected 或 private)或不存在的属性调用 unset() 时,__unset() 会被调用。
7、__call()
调用不存在或不可访问(protected 或 private)的方法时调用
8、__callStatic()
调用不存在或不可访问(protected 或 private)静态方法时调用
9、__clone()
复制对象时会执行
10、__set_state()
当调用var_export()导出类时,此方法会被调用。
var_export() 函数返回关于传递给该函数的变量的结构信息,它和 var_dump() 函数类似,不同的是其返回的表示是合法的 PHP 代码。
11、__debugInfo()
使用print_r,var_dump、print、dump等时调用,可设置打印信息格式
12、__tostring()
类被当成字符串调用时执行
13、__invoke()
类被当成方法调用时执执行
14、__sleep()
serialize()方法被执行前调用
此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。 如果该方法未返回任何内容,则 null
被序列化,并产生一个 E_NOTICE
级别的错误。
serialize() 函数用于序列化对象或数组,并返回一个字符串。
15、__wakeup()
unserialize()方法被执行前调用
经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。
unserialize() 函数用于将通过 serialize()函数序列化后的对象或数组进行反序列化,并返回原始的对象结构。
16、__serialize() 【PHP7.4+之后被引入,当同__sleep()魔术方法同时存在时,__serialize()会被执行,__sleep()会被忽略】
serialize()方法被执行前调用。
它必须以一个代表对象序列化形式的 键/值 成对的关联数组形式来返回,如果没有返回数组,将会抛出一个 TypeError 错误。
17、__unserialize() 【PHP7.4+之后被引入,当同__wakeup()魔术方法同时存在时,__unserialize()会被执行,__wakeup()会被忽略】
unserialize()方法被执行前调用
三、被废弃的魔术方法
18、__autoload() 【PHP 7.2.0 起被废弃,并自 PHP 8.0.0 起被移除】
尝试加载未被定义的类
四、最佳实践与注意事项
- 避免滥用:
魔术方法会增加代码隐性逻辑,过度使用会增加代码维护难度。日常编程时推荐优先使用常规 OOP 设计(如公共方法),仅在必要时使用魔术方法。
- 性能考量:
动态方法调用(__call/__callStatic)存在额外的函数调用开销,高频场景需谨慎评估。
- 兼容性:
部分魔术方法随着php版本的升级,逐步被弃用,如__autoload()。
- 安全控制:
在 __get/__set 等方法中,需对输入进行严格过滤,避免代码注入或数据泄露(如动态调用 __call 时验证方法名)。
五、总结
魔术方法是 PHP 面向对象编程中的“约定式钩子”,通过引擎底层的事件机制,将对象行为与生命周期深度绑定。
魔术方法的用意:
- 解耦:将通用逻辑(如日志、验证)从业务代码中分离。
- 简洁:用少量代码实现常规需要多个方法才能完成的功能。
- 灵活:动态拦截对象操作,适应复杂业务场景的动态需求。