1. PHP面向对象基础:类与对象的定义、属性与方法、访问修饰符、$this关键字、构造函数与析构函数
好,咱们正式开始。面向对象编程,说白了就是「把代码当成现实世界的东西来写」。你想想看,现实世界里有一辆汽车,它有颜色、有速度(属性),它能跑、能停(方法)。在PHP里,我们就把这种思维搬到了代码中。
我个人习惯把类比作「蓝图」,对象就是根据蓝图造出来的「实物」。蓝图本身不能开,但造出来的车可以。这个比喻我用了十年,至今觉得最贴切。
1.1 类与对象的定义
先看一个最简单的类长什么样:
<?php
class Car {
// 这里写属性和方法
}
?>
用 class 关键字,后面跟类名。类名我建议用大驼峰(每个单词首字母大写),比如 UserModel、OrderService。这是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
?>
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 对象时网络一卡,整个页面都崩了,多冤啊。
好了,这一章的内容就这些。类与对象是面向对象的基石,后面的继承、多态、设计模式全都建立在这之上。把这一章吃透,后面的路就好走了。