面向对象
class、interface、trait。
面向对象
这一课你将能做到
- 定义带可见性、类型声明属性的类,并用构造器属性提升写出紧凑的 DTO
- 用接口约束行为、用 trait 复用实现,说清两者与抽象类的分工
- 掌握 readonly 属性(8.1)与 readonly 类(8.2),写出不可变对象
为什么要学
PHP 8 之后的面向对象已经和 Java 非常接近:接口、抽象类、trait、枚举、final、类型声明一应俱全,还多了构造器属性提升这种 Java 没有的「减法语法」。现代框架的每一层——Controller、Service、Repository——都是类和接口的组合。不懂 OOP,读 Laravel 或 Symfony 源码就是读天书;懂了 OOP,你会发现两个框架的分层思想和 Spring 高度同构。
人话:类是「数据 + 行为」的模具,接口是「承诺书」(你能干什么),trait 是「外挂技能包」(横向复制实现),继承是「父子传家」。这四个工具组合起来,就是工程化的全部骨架。
先建立图像
一个典型的 PHP 服务类分层:
UserRepository ──► 查库(依赖 PDO)
UserServiceImpl ──► 业务逻辑(依赖 UserRepository 接口)
UserController ──► 接 HTTP 请求(依赖 Service 接口)
接口 UserRepositoryInterface ← 行为契约
类 MySqlUserRepository ← 一种实现
trait Loggable ← 横切能力,多个类复用
和 Spring 的 Controller/Service/Repository 分层完全对位,区别只是装配方式:PHP 在构造函数里手动 new 或由容器注入,Spring 交给 IoC 容器。
跟着做
步骤 1:类与构造器属性提升
新建 Order.php:
<?php
declare(strict_types=1);
class Order
{
// PHP 8 构造器属性提升:声明 + 赋值一行搞定
public function __construct(
private readonly int $id,
private readonly string $product,
private float $amount,
private string $status = 'pending',
) {
if ($amount < 0) {
throw new \InvalidArgumentException('金额不能为负');
}
}
public function pay(): void
{
if ($this->status !== 'pending') {
throw new \RuntimeException('订单状态不允许支付');
}
$this->status = 'paid';
}
public function status(): string
{
return $this->status;
}
}
$order = new Order(1, '机械键盘', 399.00);
$order->pay();
echo $order->status(), PHP_EOL; // paid
// $order->amount = -1; // private,外部不可直接改
对比 Java:相当于把字段声明、构造参数、赋值语句三件事压缩成一组带修饰符的参数。readonly 修饰的属性初始化后不可再改。
步骤 2:继承与可见性
<?php
declare(strict_types=1);
class Animal
{
public function __construct(protected string $name) {}
public function introduce(): string
{
return "我是 {$this->name}";
}
}
class Dog extends Animal
{
public function introduce(): string // 方法重写
{
return parent::introduce() . ',汪!';
}
}
echo (new Dog('旺财'))->introduce(), PHP_EOL; // 我是 旺财,汪!
可见性三层:public 谁都能访问, 本类和子类, 仅本类。属性不写修饰符是非法的(PHP 8 起强制),这堵死了老代码的「隐式 public」。