PHP 面向对象核心学习笔记(类、对象、魔术方法、序列化)

前言

本文整理 PHP 面向对象高频核心知识点,包含类与对象基础、访问控制、魔术方法全解、序列化与反序列化原理、安全风险。

一、类与对象基础概念

1. 核心定义

  1. 类 Class:对象的模板 / 蓝图,抽象描述一类事物共同的属性与行为,仅定义结构,不存储具体数据。
  2. 对象 Object:类的实例,通过new关键字实例化生成,拥有独立属性值,可调用类中方法;一个类可实例化多个互不干扰对象。
  3. 执行流程: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;

关键字说明

  1. class:声明类;new:实例化对象
  2. $this:类内部代表当前调用的对象,仅实例方法可用
  3. ->:对象访问属性 / 方法;:::静态访问操作符

二、三大访问修饰符(封装核心)

控制类属性、方法的访问权限,实现数据封装,禁止外部随意篡改数据。

表格

修饰符 访问范围 使用场景
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. 魔术方法通用核心特征(必背考点)

  1. 方法名统一以 ** 双下划线__** 开头,禁止自定义方法使用__前缀;
  2. 不由开发者手动调用,满足指定操作时PHP 引擎自动触发
  3. 必须定义在类内部,推荐使用public修饰,私有 / 保护会导致无法自动执行;
  4. 每个魔术方法绑定固定触发场景,功能固定,开发者仅可自定义内部逻辑;
  5. 仅有__callStatic是静态魔术方法,其余均为实例方法。

2. 生命周期类魔术方法

(1)__construct () 构造方法
  • 触发时机:new 类名()实例化对象时自动执行
  • 作用:初始化对象属性、资源连接、接收实例化参数
  • 限制:一个类仅能存在一个构造方法,不支持重载
(2)__destruct () 析构方法
  • 触发时机:对象销毁、脚本执行结束、unset($obj)主动释放时执行
  • 作用:释放数据库、文件等资源;无参数、无返回值
(3)__clone()
  • 触发时机:使用clone $obj克隆对象
  • 作用:自定义克隆后的属性,区分浅拷贝、深拷贝
(4)__sleep()
  • 触发时机:serialize()序列化对象之前
  • 要求:必须返回包含属性名的数组,仅数组内属性会被序列化;可过滤密码等敏感数据
(5)__wakeup ()(高频考点)
  • 触发时机:unserialize()反序列化还原对象之后自动执行
  • 作用:重连资源、修复数据、身份校验
  • 注意:类实现Serializable接口后,该方法不再触发

3. 属性重载魔术方法(拦截非法读写)

  1. __set($name,$value):给不存在 / 私有 / 保护属性赋值触发
  2. __get($name):读取不存在 / 私有 / 保护属性触发
  3. __isset($name):对私有属性执行isset($obj->属性)触发
  4. __unset($name)unset($obj->属性)删除私有属性触发

4. 方法重载魔术方法

  1. __call($func,$args):调用对象不存在的普通方法触发
  2. __callStatic($func,$args):调用不存在静态方法触发,必须加 static 修饰

5. 类型转换魔术方法

  1. __toString():对象被当作字符串输出(echo、print)触发,必须 return 字符串
  2. __invoke():对象直接以函数形式调用$obj()时触发

四、序列化与反序列化 serialize /unserialize

1. 作用

  • serialize(变量):将数组、对象转为结构化字符串,用于缓存、文件、数据库存储、网络传输;仅保存属性,不保存类方法。
  • unserialize(字符串):将序列化字符串还原为原始数组 / 对象。

2. 对象序列化规则

  1. 序列化仅存储属性,方法丢失;
  2. 反序列化时,当前脚本必须提前加载对应类,否则生成__PHP_Incomplete_Class残缺对象,无法调用方法;
  3. 还原对象属性完成后,自动触发__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. 安全风险

  1. 漏洞成因:若用户可控输入直接传入unserialize(),攻击者可构造恶意序列化字符串;
  2. 风险触发点:反序列化自动调用__wakeup__destruct__toString等魔术方法,执行恶意代码;
  3. 防御方案:
    • 禁止直接将 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

六、学习总结

  1. 类是模板,对象是实例,$this代表当前对象,封装依靠三大访问修饰符;
  2. 魔术方法识别特征为__前缀,自动触发,是 PHP 面向对象重载、生命周期管理核心;
  3. serialize/unserialize 用于持久化存储对象,__wakeup是反序列化标志性魔术方法;
  4. 反序列化存在高危安全漏洞,开发中必须做好白名单、输入过滤防护;
  5. 内部存储缓存可使用 serialize,前后端跨语言数据交换优先 JSON。

更多推荐