PHP面向对象编程实战:构建用户管理系统

面向对象编程(OOP)的真正价值在于实际应用。本文将通过构建一个完整的用户管理系统,展示PHP面向对象编程的核心概念在实际开发中的运用。我们将从基础类设计开始,逐步扩展功能,最终形成一个可重用的用户管理组件。

用户类的基本实现

让我们从最基本的User类开始,这个类将封装用户数据和相关操作:



class User {
    // 属性
    private $id;
    private $username;
    private $email;
    private $passwordHash;
    private $createdAt;
    private $isActive;

    // 构造函数
    public function __construct(string $username, string $email, string $password) {
        $this->username = $username;
        $this->email = $email;
        $this->setPassword($password);
        $this->createdAt = new DateTime();
        $this->isActive = true;
    }

    // Getter方法
    public function getId(): ?int {
        return $this->id;
    }

    public function getUsername(): string {
        return $this->this->username;
    }

    public function getEmail(): string {
        return $this->email;
    }

    public function getCreatedAt(): DateTime {
        return $this->createdAt;
    }

    public function isActive(): bool {
        return $this->isActive;
    }

    // Setter方法
    public function setUsername(string $username): void {
        if (empty($username)) {
            throw new InvalidArgumentException("用户名不能为空");
        }
        $this->username = $username;
    }

    public function setEmail(string $email): void {
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            throw new InvalidArgumentException("无效的邮箱格式");
        }
        $this->email = $email;
    }

    public function setPassword(string $password): void {
        if (strlen($password) < 8) {
            throw new InvalidArgumentException("密码至少需要8个字符");
        }
        $this->passwordHash = password_hash($password, PASSWORD_DEFAULT);
    }

    public function setActive(bool $isActive): void {
        $this->isActive = $isActive;
    }

    // 业务方法
    public function verifyPassword(string $password): bool {
        return password_verify($password, $this->passwordHash);
    }

    // 魔术方法
    public function __toString(): string {
        return sprintf(
            "User(id=%s, username=%s, email=%s, active=%s)",
            $this->id,
            $this->username,
            $this->email,
            $this->isActive ? 'true' : 'false'
        );
    }
}

这个基础User类展示了面向对象编程的几个关键方面:
• 封装:属性设为private,通过公共方法访问
• 数据验证:在setter方法中进行输入验证
• 业务逻辑:如密码哈希和验证
• 类型声明:PHP7+的类型提示
• 魔术方法:__toString()用于对象字符串表示

用户仓库类设计

为了持久化用户数据,我们需要创建一个UserRepository类,负责与数据库交互:



class UserRepository {
    private $pdo;

    public function __construct(PDO $pdo) {
        $this->pdo = $pdo;
    }

    public function save(User $user): User {
        if ($user->getId() === null) {
            return $this->insert($user);
        }
        return $this->update($user);
    }

    private function insert(User $user): User {
        $stmt = $this->pdo->prepare("
            INSERT INTO users (username, email, password_hash, created_at, is_active)
            VALUES (:username, :email, :password_hash, :created_at, :is_active)
        ");

        $stmt->execute([
            ':username' => $user->getUsername(),
            ':email' => $user->getEmail(),
            ':password_hash' => $user->getPasswordHash(),
            ':created_at' => $user->getCreatedAt()->format('Y-m-d H:i:s'),
            ':is_active' => $user->isActive() ? 1 : 0
        ]);

        $user->setId($this->pdo->lastInsertId());
        return $user;
    }

    private function update(User $user): User {
        $stmt = $this->pdo->prepare("
            UPDATE users SET
                username = :username,
                email = :email,
                password_hash = :password_hash,
                is_active = :is_active
            WHERE id = :id
        ");

        $stmt->execute([
            ':id' => $user->getId(),
            ':username' => $user->getUsername(),
            ':email' => $user->getEmail(),
            ':password_hash' => $user->getPasswordHash(),
            ':is_active' => $user->isActive() ? 1 : 0
        ]);

        return $user;
    }

    public function find(int $id): ?User {
        $stmt = $this->pdo->prepare("SELECT * FROM users WHERE id = :id");
        $stmt->execute([':id' => $id]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$row) {
            return null;
        }

        return $this->mapRowToUser($row);
    }

    public function findByEmail(string $email): ?User {
        $stmt = $this->pdo->prepare("SELECT * FROM users WHERE email = :email");
        $stmt->execute([':email' => $email]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$row) {
            return null;
        }

        return $this->mapRowToUser($row);
    }

    private function mapRowToUser(array $row): User {
        $user = new User($row['username'], $row['email'], '');
        $user->setId($row['id']);
        $user->setPasswordHash($row['password_hash']);
        $user->setCreatedAt(new DateTime($row['created_at']));
        $user->setActive((bool)$row['is_active']);

        return $user;
    }
}

UserRepository类展示了:
• 依赖注入:通过构造函数接收PDO实例
• 单一职责:只负责用户数据的持久化
• CRUD操作:创建、读取、更新用户数据
• 对象关系映射:将数据库行转换为User对象

服务层与异常处理

为了处理更复杂的业务逻辑,我们创建一个UserService类:



class UserService {
    private $userRepository;
    private $mailer;

    public function __construct(UserRepository $userRepository, MailerInterface $mailer) {
        $this->userRepository = $userRepository;
        $this->mailer = $mailer;
    }

    public function registerUser(string $username, string $email, string $password): User {
        // 检查邮箱是否已存在
        if ($this->userRepository->findByEmail($email) !== null) {
            throw new UserAlreadyExistsException("该邮箱已被注册");
        }

        // 创建用户
        $user = new User($username, $email, $password);
        $this->userRepository->save($user);

        // 发送欢迎邮件
        $this->mailer->sendWelcomeEmail($user);

        return $user;
    }

    public function authenticate(string $email, string $password): User {
        $user = $this->userRepository->findByEmail($email);
        
        if ($user === null) {
            throw new AuthenticationException("用户不存在");
        }

        if (!$user->isActive()) {
            throw new AccountInactiveException("账户未激活");
        }

        if (!$user->verifyPassword($password)) {
            throw new AuthenticationException("密码错误");
        }

        return $user;
    }

    public function resetPassword(string $email): void {
        $user = $this->userRepository->findByEmail($email);
        
        if ($user === null) {
            throw new UserNotFoundException("用户不存在");
        }

        $tempPassword = bin2hex(random_bytes(8));
        $user->setPassword($tempPassword);
        $this->userRepository->save($user);

        $this->mailer->sendPasswordResetEmail($user, $tempPassword);
    }
}

自定义异常类示例:

class UserAlreadyExistsException extends \RuntimeException {}
class AuthenticationException extends \RuntimeException {}
class AccountInactiveException extends \RuntimeException {}
class UserNotFoundException extends \RuntimeException {}

UserService展示了:
• 业务逻辑集中处理
• 依赖注入的应用
• 自定义异常的使用
• 与其他组件的协作

使用继承扩展功能

我们可以通过继承创建不同类型的用户:

class AdminUser extends User {
    private $permissions = [];

    public function __construct(string $username, string $email, string $password, array $permissions) {
        parent::__construct($username, $email, $password);
        $this->permissions = $permissions;
    }

    public function getPermissions(): array {
        return $this->permissions;
    }

    public function hasPermission(string $permission): bool {
        return in_array($permission, $this->permissions);
    }

    public function __toString(): string {
        return sprintf(
            "AdminUser(id=%s, username=%s, permissions=%s)",
            $this->getId(),
            $this->getUsername(),
            implode(', ', $this->permissions)
        );
    }
}

接口与多态应用

定义邮件发送器接口和实现:

interface MailerInterface {
    public function sendWelcomeEmail(User $user): void;
    public function sendPasswordResetEmail(User $user, string $tempPassword): void;
}

class SmtpMailer implements MailerInterface {
    public function sendWelcomeEmail(User $user): void {
        // 实现SMTP发送欢迎邮件的逻辑
        echo "发送欢迎邮件到: " . $user->getEmail() . "\n";
    }

    public function sendPasswordResetEmail(User $user, string $tempPassword): void {
        // 实现SMTP发送密码重置邮件的逻辑
        echo "发送密码重置邮件到: " . $user->getEmail() . ", 临时密码: " . $tempPassword . "\n";
    }
}

class MockMailer implements MailerInterface {
    public function sendWelcomeEmail(User $user): void {
        // 测试环境下不实际发送邮件
        echo "[测试] 模拟发送欢迎邮件到: " . $user->getEmail() . "\n";
    }

    public function sendPasswordResetEmail(User $user, string $tempPassword): void {
        // 测试环境下不实际发送邮件
        echo "[测试] 模拟发送密码重置邮件到: " . $user->getEmail() . "\n";
    }
}

完整的示例应用

将所有部分组合起来:

// 初始化组件
$pdo = new PDO('mysql:host=localhost;dbname=test', 'username', 'password');
$userRepository = new UserRepository($pdo);
$mailer = new SmtpMailer();
$userService = new UserService($userRepository, $mailer);

// 注册新用户
try {
    $user = $userService->registerUser('john_doe', '[email protected]', 'secure123');
    echo "用户注册成功: " . $user . "\n";
} catch (UserAlreadyExistsException $e) {
    echo "错误: " . $e->getMessage() . "\n";
}

// 用户登录
try {
    $user = $userService->authenticate('[email protected]', 'secure123');
    echo "登录成功: " . $user->getUsername() . "\n";
} catch (AuthenticationException $e) {
    echo "登录失败: " . $e->getMessage() . "\n";
}

// 重置密码
try {
    $userService->resetPassword('[email protected]');
    echo "密码重置邮件已发送\n";
} catch (UserNotFoundException $e) {
    echo "错误: " . $e->getMessage() . "\n";
}

总结与最佳实践

通过这个用户管理系统的实现,我们展示了PHP面向对象编程在实际项目中的应用。总结一些关键实践:

  1. 分层架构:将代码分为实体类(User)、数据访问层(UserRepository)、业务逻辑层(UserService)和表示层(未展示)

  2. 依赖注入:通过构造函数注入依赖,提高可测试性和灵活性

  3. 异常处理:使用自定义异常明确区分不同类型的错误

  4. 接口编程:依赖接口而非具体实现,如MailerInterface

  5. SOLID原则
    • 单一职责:每个类只做一件事
    • 开闭原则:通过继承和接口扩展而非修改
    • 里氏替换:子类可以替换父类
    • 接口隔离:定义专门的接口
    • 依赖倒置:高层模块不依赖低层模块

  6. 类型安全:使用PHP7+的类型声明提高代码可靠性

  7. 封装:保护对象内部状态,通过方法控制访问

这个示例展示了如何将面向对象编程的理论转化为实际可用的代码。在实际项目中,你还可以考虑添加更多功能,如:
• 使用Trait实现横切关注点
• 实现观察者模式处理用户事件
• 添加DTO(数据传输对象)进行API通信
• 使用工厂模式创建复杂对象

面向对象编程是一门需要不断实践的技能,通过构建这样的实际项目,你将更深入地理解如何设计灵活、可维护的PHP应用程序。

你可能感兴趣的:(php,android,开发语言)