PHP 面向对象(类、对象、魔术方法、序列化)
·
PHP 面向对象核心学习笔记(类、对象、魔术方法、序列化)
前言
本文整理 PHP 面向对象高频核心知识点,包含类与对象基础、访问控制、魔术方法全解、序列化与反序列化原理、安全风险。
一、类与对象基础概念
1. 核心定义
- 类 Class:对象的模板 / 蓝图,抽象描述一类事物共同的属性与行为,仅定义结构,不存储具体数据。
- 对象 Object:类的实例,通过
new关键字实例化生成,拥有独立属性值,可调用类中方法;一个类可实例化多个互不干扰对象。 - 执行流程:
class 模板→new实例化 → 生成对象。
2. 基础语法示例
// 定义类
class Student{
// 成员属性
public string $name;
public int $age;
// 构造方法,实例化自动执行
public function __construct(string $name, int $age){
$this->name = $name;
$this->age = $age;
}
// 成员方法
public function introduce(){
echo "我是{$this->name},今年{$this->age}岁";
}
}
// 创建对象
$stu1 = new Student("小明", 18);
$stu1->introduce();
echo $stu1->name;
关键字说明
class:声明类;new:实例化对象$this:类内部代表当前调用的对象,仅实例方法可用->:对象访问属性 / 方法;:::静态访问操作符
二、三大访问修饰符(封装核心)
控制类属性、方法的访问权限,实现数据封装,禁止外部随意篡改数据。
表格
| 修饰符 | 访问范围 | 使用场景 |
|---|---|---|
| public | 类内、类外、子类均可访问 | 对外暴露接口 |
| protected | 当前类 + 子类可访问,外部禁止 | 继承复用的通用属性 |
| private | 仅当前类内部访问,子类、外部均不可见 | 隐私数据(手机号、密码) |
封装标准写法
私有属性搭配get/set方法,增加数据校验:
class User{
private string $phone;
// 获取手机号
public function getPhone():string{
return $this->phone;
}
// 赋值并校验
public function setPhone(string $phone):void{
if(strlen($phone) === 11){
$this->phone = $phone;
}
}
}
三、魔术方法完整详解
1. 魔术方法通用核心特征(必背考点)
- 方法名统一以 ** 双下划线
__** 开头,禁止自定义方法使用__前缀; - 不由开发者手动调用,满足指定操作时PHP 引擎自动触发;
- 必须定义在类内部,推荐使用
public修饰,私有 / 保护会导致无法自动执行; - 每个魔术方法绑定固定触发场景,功能固定,开发者仅可自定义内部逻辑;
- 仅有
__callStatic是静态魔术方法,其余均为实例方法。
2. 生命周期类魔术方法
(1)__construct () 构造方法
- 触发时机:
new 类名()实例化对象时自动执行 - 作用:初始化对象属性、资源连接、接收实例化参数
- 限制:一个类仅能存在一个构造方法,不支持重载
(2)__destruct () 析构方法
- 触发时机:对象销毁、脚本执行结束、
unset($obj)主动释放时执行 - 作用:释放数据库、文件等资源;无参数、无返回值
(3)__clone()
- 触发时机:使用
clone $obj克隆对象 - 作用:自定义克隆后的属性,区分浅拷贝、深拷贝
(4)__sleep()
- 触发时机:
serialize()序列化对象之前 - 要求:必须返回包含属性名的数组,仅数组内属性会被序列化;可过滤密码等敏感数据
(5)__wakeup ()(高频考点)
- 触发时机:
unserialize()反序列化还原对象之后自动执行 - 作用:重连资源、修复数据、身份校验
- 注意:类实现
Serializable接口后,该方法不再触发
3. 属性重载魔术方法(拦截非法读写)
__set($name,$value):给不存在 / 私有 / 保护属性赋值触发__get($name):读取不存在 / 私有 / 保护属性触发__isset($name):对私有属性执行isset($obj->属性)触发__unset($name):unset($obj->属性)删除私有属性触发
4. 方法重载魔术方法
__call($func,$args):调用对象不存在的普通方法触发__callStatic($func,$args):调用不存在静态方法触发,必须加 static 修饰
5. 类型转换魔术方法
__toString():对象被当作字符串输出(echo、print)触发,必须 return 字符串__invoke():对象直接以函数形式调用$obj()时触发
四、序列化与反序列化 serialize /unserialize
1. 作用
serialize(变量):将数组、对象转为结构化字符串,用于缓存、文件、数据库存储、网络传输;仅保存属性,不保存类方法。unserialize(字符串):将序列化字符串还原为原始数组 / 对象。
2. 对象序列化规则
- 序列化仅存储属性,方法丢失;
- 反序列化时,当前脚本必须提前加载对应类,否则生成
__PHP_Incomplete_Class残缺对象,无法调用方法; - 还原对象属性完成后,自动触发
__wakeup()魔术方法。
3. 基础示例
class User{
public $name;
public function __wakeup(){
echo "反序列化完成,执行__wakeup";
}
}
$user = new User();
$user->name = "张三";
// 序列化
$str = serialize($user);
// 反序列化
$obj = unserialize($str);
echo $obj->name;
4. unserialize 安全参数
第二个参数配置白名单,防御反序列化漏洞:
// 仅允许反序列化User类,禁止其他类
$obj = unserialize($str, [
'allowed_classes' => ['User']
]);
5. 安全风险
- 漏洞成因:若用户可控输入直接传入
unserialize(),攻击者可构造恶意序列化字符串; - 风险触发点:反序列化自动调用
__wakeup、__destruct、__toString等魔术方法,执行恶意代码; - 防御方案:
- 禁止直接将 GET/POST/COOKIE 用户数据传入 unserialize;
- 使用
allowed_classes配置类白名单; - 跨语言传输优先使用
json_encode/json_decode替代序列化; - 序列化字符串增加加盐哈希校验完整性。
6. serialize 无法序列化内容
资源句柄(数据库连接、打开的文件)、匿名闭包 Closure,序列化后数据失效。
五、serialize 与 json_encode 对比
表格
| 对比项 | serialize() | json_encode() |
|---|---|---|
| 对象支持 | 完整保存私有、保护、公有属性 | 仅序列化公有属性 |
| 跨语言 | 仅 PHP 可解析 | JS、Java、Python 通用 |
| 可读性 | 加密式字符串,难以阅读 | 标准 JSON,格式清晰 |
| 还原结果 | unserialize 直接得到原对象 | json_decode 仅数组 /stdClass |
六、学习总结
- 类是模板,对象是实例,
$this代表当前对象,封装依靠三大访问修饰符; - 魔术方法识别特征为
__前缀,自动触发,是 PHP 面向对象重载、生命周期管理核心; - serialize/unserialize 用于持久化存储对象,
__wakeup是反序列化标志性魔术方法; - 反序列化存在高危安全漏洞,开发中必须做好白名单、输入过滤防护;
- 内部存储缓存可使用 serialize,前后端跨语言数据交换优先 JSON。
更多推荐
所有评论(0)