PHP: 实战:面向对象综合
学了 5 课面向对象,知识都在脑子里。这节课把它们焊在一起——两个项目:一个完整覆盖继承/枚举/Trait/接口的用户系统,一个让你初窥 MVC 架构的简易框架。
1. 项目一:用户角色管理系统
综合运用类、继承、枚举、Trait、接口,搭建一个完整的用户角色管理框架。
▶ 示例:完整 OOP 用户系统
PHP
📖 仅展示
<?php
// === 枚举 ===
enum UserRole: string {
case ADMIN = 'admin';
case EDITOR = 'editor';
case MEMBER = 'member';
case GUEST = 'guest';
}
enum UserStatus: string {
case ACTIVE = 'active';
case INACTIVE = 'inactive';
case BANNED = 'banned';
}
// === 接口 ===
interface Loggable {
public function getLogIdentifier(): string;
}
interface Manageable {
public function canAccess(string $resource): bool;
public function getPermissions(): array;
}
// === Trait ===
trait HasTimestamps {
public readonly string $createdAt;
public readonly string $updatedAt;
public function touch(): void {
$now = date("Y-m-d H:i:s");
if (!isset($this->createdAt)) {
$this->createdAt = $now;
}
$this->updatedAt = $now;
}
}
trait ArraySerializable {
public function toArray(): array {
return get_object_vars($this);
}
}
// === 基类 ===
abstract class User implements Loggable, Manageable {
use HasTimestamps, ArraySerializable;
public function __construct(
public readonly string $id,
public string $name,
public string $email,
public UserRole $role = UserRole::MEMBER,
public UserStatus $status = UserStatus::ACTIVE,
) {
$this->touch();
}
public function getLogIdentifier(): string {
return "User#{$this->id} ({$this->name})";
}
abstract public function canAccess(string $resource): bool;
abstract public function getPermissions(): array;
abstract public function getRoleLabel(): string;
}
// === 具体角色类 ===
class Admin extends User {
public function __construct(
string $id, string $name, string $email
) {
parent::__construct($id, $name, $email, UserRole::ADMIN);
}
public function canAccess(string $resource): bool {
return true; // 管理员能访问一切
}
public function getPermissions(): array {
return ['create', 'read', 'update', 'delete', 'manage_users', 'system_config'];
}
public function getRoleLabel(): string {
return '🔧 管理员';
}
}
class Editor extends User {
public function __construct(
string $id, string $name, string $email
) {
parent::__construct($id, $name, $email, UserRole::EDITOR);
}
public function canAccess(string $resource): bool {
return in_array($resource, ['articles', 'media', 'comments']);
}
public function getPermissions(): array {
return ['create', 'read', 'update', 'manage_comments'];
}
public function getRoleLabel(): string {
return '✏️ 编辑';
}
}
class Member extends User {
public function __construct(
string $id, string $name, string $email
) {
parent::__construct($id, $name, $email, UserRole::MEMBER);
}
public function canAccess(string $resource): bool {
return in_array($resource, ['articles', 'comments', 'profile']);
}
public function getPermissions(): array {
return ['read', 'comment'];
}
public function getRoleLabel(): string {
return '👤 会员';
}
}
// === 权限管理器 ===
class AccessManager {
public function checkAccess(User $user, string $resource): string {
if ($user->status === UserStatus::BANNED) {
return "{$user->getRoleLabel()} {$user->name}:已封禁,拒绝访问 {$resource}";
}
$allowed = $user->canAccess($resource)
? "✅ 允许访问" : "❌ 拒绝访问";
return "{$user->getRoleLabel()} {$user->name}:{$allowed} {$resource}";
}
public function listAllAccess(array $users, array $resources): void {
foreach ($users as $user) {
echo "<h4>{$user->getLogIdentifier()}</h4>";
echo "权限:" . implode(', ', $user->getPermissions()) . "<br>";
foreach ($resources as $res) {
echo $this->checkAccess($user, $res) . "<br>";
}
}
}
}
// === 测试系统 ===
$users = [
new Admin("u1", "小明", "admin@example.com"),
new Editor("u2", "小红", "editor@example.com"),
new Member("u3", "小刚", "member@example.com"),
];
$resources = ['articles', 'media', 'comments', 'system_config', 'manage_users'];
$manager = new AccessManager();
$manager->listAllAccess($users, $resources);
// 测试枚举 + 序列化
echo "<br>Admin 数据:" . json_encode($users[0]->toArray(), JSON_UNESCAPED_UNICODE);
?>
2. 项目二:简易 MVC 框架
理解路由、控制器、视图的 MVC 概念——这是 Laravel 等框架的核心思想。
▶ 示例:迷你 MVC
PHP
📖 仅展示
<?php
// === Router 路由类 ===
class Router {
private array $routes = [];
public function get(string $path, callable $handler): void {
$this->routes['GET'][$path] = $handler;
}
public function post(string $path, callable $handler): void {
$this->routes['POST'][$path] = $handler;
}
public function dispatch(string $method, string $uri): void {
$path = parse_url($uri, PHP_URL_PATH);
$handler = $this->routes[$method][$path] ?? null;
if ($handler) {
echo $handler($_GET);
} else {
http_response_code(404);
echo "<h2>404 — 页面未找到</h2>";
}
}
}
// === View 视图基类 ===
class View {
public static function render(string $template, array $data = []): string {
extract($data);
ob_start();
include __DIR__ . "/{$template}.php";
return ob_get_clean();
}
}
// === Controller 控制器基类 ===
abstract class Controller {
protected function json(array $data, int $code = 200): void {
http_response_code($code);
header('Content-Type: application/json; charset=utf-8');
echo json_encode($data, JSON_UNESCAPED_UNICODE);
}
}
// === 具体控制器 ===
class HomeController extends Controller {
public function index(): void {
echo View::render('home', [
'title' => '首页',
'message' => '欢迎来到我的博客!',
]);
}
public function about(): void {
echo View::render('about', [
'title' => '关于我们',
'team' => ['小明', '小红', '小刚'],
'version' => '1.0.0',
]);
}
public function api(): void {
$this->json([
'status' => 'ok',
'data' => ['version' => '1.0.0', 'uptime' => time()],
]);
}
}
// === 设置路由 ===
$router = new Router();
$home = new HomeController();
$router->get('/', fn() => $home->index());
$router->get('/about', fn() => $home->about());
$router->get('/api/status', fn() => $home->api());
// === 启动应用 ===
$router->dispatch($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
?>
配套的视图文件 home.php:
PHP
<!DOCTYPE html>
<html lang="zh">
<head><title><?= $title ?></title></head>
<body>
<h1><?= $message ?></h1>
<p>这是一个用 MVC 思想构建的页面。</p>
</body>
</html>
3. 感悟:从过程式到 OOP 的思维跃迁
| 过程式思路 | OOP 思路 |
|---|---|
"我要读取用户数据" → 写个 getUser() 函数 |
"用户是什么?有什么属性和行为?" → 设计 User 类 |
| 数据和函数分散在各文件 | 数据+行为封装在类里 |
| 代码重复了 → 复制粘贴或抽函数 | 代码重复了 → 用继承或 Trait |
传 'admin' 字符串判断权限 |
传 UserRole::ADMIN 枚举,类型安全 |
💡 提示: OOP 不是目的,是手段。小脚本过程式完全够。当你的代码出现这些信号时转向 OOP:(1) 相同参数在多个函数间传递;(2) 全局变量越来越多;(3) 条件判断基于"类型字符串"(
if ($role === 'admin'))。
❓ 常见问题
Q MVC 中 Controller 到底做什么?
A Controller 是"交通指挥员"——接收请求、调用 Model 获取数据、选择 View 渲染。它自己不处理业务逻辑(那是 Model 的事),也不写 HTML(那是 View 的事)。
Q 写框架和用框架怎么抉择?
A 学习阶段自己写迷你框架理解原理(就像这课做的),生产环境用 Laravel/Symfony。自己做一遍 Router/Controller/View 后,用 Laravel 时你会说"哦,原来背后是这样"。
❓ 常见问题
Q 这个概念和 XXX 有什么区别?
A 简洁对比两者的核心差异和使用场景。
📖 小节
- 用户系统综合了枚举/继承/接口/Trait/多态五大 OOP 机制
abstract class User定义用户蓝图,子类实现具体角色能力AccessManager用多态统一处理不同角色的权限检查- MVC 思想:Router 分发请求 → Controller 协调 → View 渲染
- OOP 不是万能药,代码超过 500 行 / 出现重复逻辑 / 依赖全局变量时再考虑
📝 作业
- 基于用户系统,新增
Guest角色(只能访问 articles,无任何编辑权限),并添加到测试中。 - 给路由器增加
addRoute('GET/POST', $path, $handler)方法,让一条语句注册两种方法。 - 在 MVC 框架中增加一个
UserController,实现用户列表(从数组读取)和用户详情页(通过 ID 查询)。