PHP: 类与对象
你写了 21 课的过程式代码,可能开始觉得代码一多就乱了。面向对象编程(OOP)就是来解决这个问题的——把相关的数据和函数打包成"类",让代码更有组织、更容易复用。
1. 为什么需要类和对象?
用现实世界类比:
TEXT
📖 仅展示
过程式:你每次做蛋糕都列清单——打鸡蛋→加面粉→搅拌→烘烤
面向对象:你有个"蛋糕机"(类),按"制作"按钮就出蛋糕(对象)
用代码对比:
PHP
<?php
// 过程式:数据和函数分散
$userName = "小明";
$userAge = 25;
function greet($name) {
return "你好,{$name}";
}
echo greet($userName);
// 面向对象:数据和函数打包在一起
class User {
public string $name;
public int $age;
function greet(): string {
return "你好,{$this->name}";
}
}
$user = new User();
$user->name = "小明";
$user->age = 25;
echo $user->greet();
?>
💡 提示: OOP 不是"更好"的编程方式——它是组织复杂代码的工具。小脚本用过程式更简单,当代码超过 500 行时 OOP 的优势才显现。
2. 定义类
PHP
<?php
class Car {
// 属性(数据)
public string $brand;
public string $color;
public int $year;
// 方法(行为)
public function start(): string {
return "{$this->brand} 启动了!";
}
public function honk(): string {
return "嘟嘟!";
}
}
?>
语法要点:
class关键字定义类,类名用大驼峰PascalCase- 属性声明
public string $name;(PHP 7.4+ 支持类型声明) $this在方法内部引用当前对象
3. 创建对象
类只是"蓝图",需要通过 new 关键字创建具体的"对象":
PHP
<?php
// 从蓝图(类)创建3辆具体的车(对象)
$car1 = new Car();
$car1->brand = "丰田";
$car1->color = "白色";
$car1->year = 2024;
$car2 = new Car();
$car2->brand = "宝马";
$car2->color = "黑色";
$car2->year = 2023;
echo $car1->start(); // 丰田 启动了!
echo $car2->start(); // 宝马 启动了!
// 箭头运算符 -> 访问属性和方法
echo $car1->brand; // 丰田
$car1->color = "红色"; // 修改属性
echo $car1->color; // 红色
?>
4. 构造函数 __construct
构造函数在 new 时自动调用,用来初始化对象:
PHP
<?php
class Car {
public string $brand;
public string $color;
public int $year;
// 构造函数
public function __construct(string $brand, string $color, int $year) {
$this->brand = $brand;
$this->color = $color;
$this->year = $year;
}
public function getInfo(): string {
return "{$this->year}款 {$this->color} {$this->brand}";
}
}
// 创建对象时传参
$car = new Car("丰田", "白色", 2024);
echo $car->getInfo(); // 2024款 白色 丰田
?>
💡 提示:
$this->brand = $brand 左边 $this->brand 是属性,右边 $brand 是参数。PHP 8.0+ 可以直接用构造函数属性提升(constructor promotion),见下面。
▶ 示例:PHP 8 构造函数属性提升
PHP
<?php
// PHP 8.0+ 简化写法
class Car {
public function __construct(
public string $brand,
public string $color,
public int $year,
) {
// 参数自动成为属性!不用再写 $this->brand = $brand
}
}
$car = new Car("丰田", "白色", 2024);
echo $car->brand; // 丰田 ✅
?>
💡 提示: 这是 PHP 8 的一大改进——构造函数属性提升让代码减少了一半。新项目都推荐用这种写法。
5. 访问修饰符
控制属性和方法的"可见性":
PHP
<?php
class BankAccount {
public string $bank = "中国银行"; // 任何人可见、可改
private float $balance = 0; // 只有类内部可访问
protected string $accountId; // 只为内部+子类可访问
public function __construct(
private string $owner,
private float $initialDeposit = 0.0
) {
$this->balance = $initialDeposit;
}
// 通过公开方法安全地操作私有属性
public function deposit(float $amount): void {
if ($amount > 0) {
$this->balance += $amount;
}
}
public function getBalance(): float {
return $this->balance;
}
}
$account = new BankAccount("小明", 1000);
echo $account->bank; // 中国银行 ✅ public 可访问
$account->deposit(500); // ✅ public 方法可调用
echo $account->getBalance(); // 1500 ✅
// echo $account->balance; // ❌ Error: private 属性不可直接访问
// $account->balance = 9999; // ❌ Error: 不能随便改余额
?>
| 修饰符 | 别名 | 访问范围 |
|---|---|---|
public |
公开 | 任何地方都能访问 |
protected |
受保护 | 当前类和子类内 |
private |
私有 | 仅当前类内 |
💡 提示: 属性用
private 或 protected,通过公开方法访问——这叫"封装"。它让你能控制数据的修改方式,比如 deposit() 能加金额校验。
6. 对象比较
PHP
<?php
class User {
public function __construct(
public string $name,
public int $age
) {}
}
$u1 = new User("小明", 25);
$u2 = new User("小明", 25);
$u3 = $u1;
var_dump($u1 == $u2); // true(属性值相同)
var_dump($u1 === $u2); // false(不是同一个对象)
var_dump($u1 === $u3); // true(指向同一个对象)
?>
7. 完整示例:用户类
▶ 示例:完整的 User 类
PHP
<?php
class User {
private string $passwordHash; // 密码哈希,绝对不暴露
public function __construct(
public string $username,
public string $email,
string $password, // 普通参数(不是属性)
public int $age = 0,
public bool $isActive = true,
) {
// 密码在构造时就加密
$this->passwordHash = password_hash($password, PASSWORD_DEFAULT);
}
public function verifyPassword(string $password): bool {
return password_verify($password, $this->passwordHash);
}
public function getDisplayName(): string {
return $this->username . ($this->isActive ? '' : '(已停用)');
}
public function greet(): string {
return "你好,{$this->username}!你的邮箱是 {$this->email}。";
}
}
// 使用
$user = new User("小明", "xiaoming@example.com", "secret123", 25);
echo $user->greet();
echo "用户状态:" . $user->getDisplayName() . "<br>";
if ($user->verifyPassword("secret123")) {
echo "密码正确!";
}
// echo $user->passwordHash; // ❌ Error: private 不可访问
?>
❓ 常见问题
Q 什么时候用类,什么时候用函数就够了?
A 当数据和操作这些数据的函数自然成组时,用类。比如"用户"有 name/age/email 属性和 login/logout 方法。如果只是几个无关的工具函数,普通函数就够。
Q
$this 是什么?A
$this 是在对象方法中引用"当前正在操作的这个对象"。比如 $car1->start() 内部,$this 指的就是 $car1。Q 为什么不用
var 声明属性?A PHP 4 时代的语法,已过时。现代 PHP 一律用
public/private/protected + 类型声明。📖 小节
class定义蓝图,new创建对象$this在方法内引用当前对象__construct()在 new 时自动执行,初始化对象- PHP 8 构造函数属性提升:
public string $name直接写在参数里 public/private/protected控制可见性- 封装:属性 private + 方法 public,控制数据修改方式
📝 作业
- 创建一个
Book类,包含属性 title/author/price,构造函数初始化,方法getInfo()返回书籍信息。 - 创建一个
BankAccount类,private 余额、public 存款和取款方法(取款不能超余额)、public 查看余额方法。创建几个账户测试操作。 - 使用 PHP 8 构造函数属性提升重写第一题,看看少了多少行代码。