1. PHP面向对象基础:类与对象的定义、属性与方法、访问修饰符、$this关键字、构造函数与析构函数

好,咱们正式开始。面向对象编程,说白了就是「把代码当成现实世界的东西来写」。你想想看,现实世界里有一辆汽车,它有颜色、有速度(属性),它能跑、能停(方法)。在PHP里,我们就把这种思维搬到了代码中。

我个人习惯把类比作「蓝图」,对象就是根据蓝图造出来的「实物」。蓝图本身不能开,但造出来的车可以。这个比喻我用了十年,至今觉得最贴切。

1.1 类与对象的定义

先看一个最简单的类长什么样:

<?php
class Car {
    // 这里写属性和方法
}
?>

class 关键字,后面跟类名。类名我建议用大驼峰(每个单词首字母大写),比如 UserModelOrderService。这是PHP社区不成文的规矩,你遵守了,别人看你的代码就舒服。

有了类,怎么造对象?用 new 关键字:

$myCar = new Car();
$yourCar = new Car();

你看,一个蓝图,造出了两辆不同的车。它们各自独立,互不干扰。我在项目中遇到过新手把对象当全局变量用,结果两个请求互相污染数据——嗯,那是另一个故事了。

1.2 属性与方法

属性就是类里面的变量,方法就是类里面的函数。咱们给 Car 加点料:

<?php
class Car {
    public $color = '白色';
    public $speed = 0;

    public function run() {
        echo '汽车正在行驶,速度:' . $this->speed . ' km/h';
    }

    public function stop() {
        $this->speed = 0;
        echo '汽车已停止';
    }
}
?>

这里 $color$speed 是属性,run()stop() 是方法。注意看方法里的 $this,它指向当前对象。为什么要用它?因为方法不知道外面哪个对象在调用它,$this 就是「我自己」的意思。

小技巧: 我刚开始学的时候,总忘记写 $this->,结果报错说变量未定义。记住:在类的方法里访问属性,必须用 $this->属性名,不能直接写 $属性名

1.3 访问修饰符:public、protected、private

这三个词,说白了就是控制「谁能碰」的权限开关。我见过太多项目因为滥用 public 导致代码像筛子一样到处漏风。

修饰符 本类内部 子类内部 外部代码
public ✅ 可以 ✅ 可以 ✅ 可以
protected ✅ 可以 ✅ 可以 ❌ 不行
private ✅ 可以 ❌ 不行 ❌ 不行

举个例子:

<?php
class Person {
    public $name = '张三';      // 谁都能看
    protected $age = 25;       // 自己和家人能看
    private $salary = 10000;   // 只有自己知道
}

$p = new Person();
echo $p->name;      // 正常输出
echo $p->age;       // 报错!外部不能访问 protected
echo $p->salary;    // 报错!外部不能访问 private
?>
避坑指南: 我曾经接手过一个遗留系统,里面所有属性全是 public。结果业务逻辑散落在各个控制器里,到处都在直接修改对象的属性。改一个地方,炸一片。后来我花了整整两周重构,把所有属性改成 private,只暴露必要的方法。血的教训:能用 private 就别用 protected,能用 protected 就别用 public。

1.4 $this 关键字

$this 是PHP面向对象里最常用的关键字之一。它代表「当前对象」的引用。为什么需要它?因为类是一个模板,方法要被不同的对象调用,方法内部怎么知道是哪个对象在调用自己?

<?php
class Dog {
    public $name;

    public function bark() {
        echo $this->name . ' 在汪汪叫';
    }
}

$dog1 = new Dog();
$dog1->name = '旺财';
$dog1->bark();  // 输出:旺财 在汪汪叫

$dog2 = new Dog();
$dog2->name = '来福';
$dog2->bark();  // 输出:来福 在汪汪叫
?>

你看,同一个 bark() 方法,因为 $this 的存在,能准确知道当前是哪个狗在叫。如果没有 $this,方法就不知道 $name 是谁的。

1.5 构造函数与析构函数

构造函数 __construct() 是对象创建时自动调用的方法。我习惯用它来做初始化工作,比如给属性赋初始值、连接数据库等。

<?php
class User {
    private $username;
    private $createdAt;

    // 构造函数:对象一创建就执行
    public function __construct($username) {
        $this->username = $username;
        $this->createdAt = date('Y-m-d H:i:s');
        echo '用户 ' . $username . ' 已创建';
    }

    public function getInfo() {
        return '用户名:' . $this->username . ',创建时间:' . $this->createdAt;
    }
}

$user = new User('小明');
echo $user->getInfo();
// 输出:
// 用户 小明 已创建
// 用户名:小明,创建时间:2024-01-15 10:30:00
?>

析构函数 __destruct() 则相反,对象被销毁时自动调用。PHP会在脚本结束或对象不再被引用时自动销毁对象。

<?php
class Database {
    private $connection;

    public function __construct() {
        // 模拟连接数据库
        $this->connection = '数据库连接已建立';
        echo '构造函数:' . $this->connection . '<br>';
    }

    public function __destruct() {
        // 关闭数据库连接
        echo '析构函数:数据库连接已关闭';
    }
}

$db = new Database();
// 脚本结束时,自动调用 __destruct()
?>
重点记忆:
  • 构造函数:对象创建时自动执行,适合做初始化
  • 析构函数:对象销毁时自动执行,适合做清理工作(关闭文件、断开连接等)
  • PHP 5 之后,构造函数统一用 __construct(),不再支持与类名同名的方法

我记得刚入行时,有个同事在构造函数里写了大量业务逻辑,导致 new 一个对象就执行一堆操作,调试起来特别痛苦。后来我养成了一个习惯:构造函数只做「赋值」和「轻量初始化」,复杂的逻辑放到专门的方法里。你想想看,如果构造函数里调了外部API,那 new 对象时网络一卡,整个页面都崩了,多冤啊。

好了,这一章的内容就这些。类与对象是面向对象的基石,后面的继承、多态、设计模式全都建立在这之上。把这一章吃透,后面的路就好走了。