本文目录导读:

- 最简单:使用PDO封装(适合小项目)
- ActiveRecord模式(熟悉但易混淆)
- Data Mapper模式(复杂但干净)
- 实战推荐:基于PDO的仓库(Repository)模式
- 完整项目结构建议
- 使用第三方ORM(生产推荐)
- 关键注意事项
- 选择建议
在PHP项目中实现数据模型,通常有三种主流方式:原生PDO封装、ActiveRecord模式、Data Mapper模式,下面我会从基础到进阶,给出完整的实现方案和代码示例。
最简单:使用PDO封装(适合小项目)
这是最轻量的方式,适合没有ORM框架的简单项目。
// User.php - 数据模型类
class User {
private $pdo;
public function __construct(PDO $pdo) {
$this->pdo = $pdo;
}
public function find($id) {
$stmt = $this->pdo->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$id]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
public function findByEmail($email) {
$stmt = $this->pdo->prepare('SELECT * FROM users WHERE email = ?');
$stmt->execute([$email]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
public function create(array $data) {
$sql = 'INSERT INTO users (name, email, password) VALUES (?, ?, ?)';
$stmt = $this->pdo->prepare($sql);
return $stmt->execute([
$data['name'],
$data['email'],
password_hash($data['password'], PASSWORD_DEFAULT)
]);
}
}
使用示例:
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');
$userModel = new User($pdo);
$user = $userModel->findByEmail('user@example.com');
ActiveRecord模式(熟悉但易混淆)
Laravel的Eloquent、ThinkPHP的Model都采用此模式。
// User.php - 使用ActiveRecord模式
class User {
protected $pdo;
protected $table = 'users';
public $id;
public $name;
public $email;
public function __construct(PDO $pdo, array $data = []) {
$this->pdo = $pdo;
foreach ($data as $key => $value) {
if (property_exists($this, $key)) {
$this->$key = $value;
}
}
}
// 查找并返回模型实例
public static function find(PDO $pdo, $id) {
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$id]);
$data = $stmt->fetch(PDO::FETCH_ASSOC);
return $data ? new self($pdo, $data) : null;
}
// 保存当前实例(插入或更新)
public function save() {
if ($this->id) {
// 更新
$stmt = $this->pdo->prepare(
"UPDATE users SET name = ?, email = ? WHERE id = ?"
);
return $stmt->execute([$this->name, $this->email, $this->id]);
} else {
// 插入
$stmt = $this->pdo->prepare(
"INSERT INTO users (name, email) VALUES (?, ?)"
);
$result = $stmt->execute([$this->name, $this->email]);
if ($result) {
$this->id = $this->pdo->lastInsertId();
}
return $result;
}
}
// 删除
public function delete() {
if (!$this->id) return false;
$stmt = $this->pdo->prepare("DELETE FROM users WHERE id = ?");
return $stmt->execute([$this->id]);
}
}
Data Mapper模式(复杂但干净)
像Doctrine 2采用此模式,模型完全与数据库解耦。
// 1. 实体类 - 纯数据对象
class UserEntity {
private $id;
private $name;
private $email;
public function getId() { return $this->id; }
public function getName() { return $this->name; }
public function setName($name) { $this->name = $name; }
public function getEmail() { return $this->email; }
public function setEmail($email) { $this->email = $email; }
}
// 2. 映射器 - 负责数据库操作
class UserMapper {
private $pdo;
public function __construct(PDO $pdo) {
$this->pdo = $pdo;
}
public function find($id): ?UserEntity {
$stmt = $this->pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$id]);
$data = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$data) return null;
$user = new UserEntity();
$user->setId($data['id']); // 需要额外加setId方法
$user->setName($data['name']);
$user->setEmail($data['email']);
return $user;
}
public function save(UserEntity $user) {
$id = $user->getId();
if ($id) {
$stmt = $this->pdo->prepare("UPDATE users SET name=?, email=? WHERE id=?");
return $stmt->execute([$user->getName(), $user->getEmail(), $id]);
} else {
$stmt = $this->pdo->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
$result = $stmt->execute([$user->getName(), $user->getEmail()]);
if ($result) {
$user->setId($this->pdo->lastInsertId());
}
return $result;
}
}
}
实战推荐:基于PDO的仓库(Repository)模式
这是目前最推荐的实践方式,结合了简洁与清晰。
// repositories/UserRepository.php
class UserRepository {
private $pdo;
public function __construct(PDO $pdo) {
$this->pdo = $pdo;
}
public function findById($id): ?array {
$stmt = $this->pdo->prepare("SELECT * FROM users WHERE id = ? AND deleted_at IS NULL");
$stmt->execute([$id]);
return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
}
public function findByEmail($email): ?array {
$stmt = $this->pdo->prepare("SELECT * FROM users WHERE email = ?");
$stmt->execute([$email]);
return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
}
public function findAll(int $page = 1, int $perPage = 20): array {
$offset = ($page - 1) * $perPage;
$stmt = $this->pdo->prepare(
"SELECT * FROM users ORDER BY created_at DESC LIMIT ? OFFSET ?"
);
$stmt->execute([$perPage, $offset]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
public function save(array $data): int {
$stmt = $this->pdo->prepare(
"INSERT INTO users (name, email, password, created_at) VALUES (?, ?, ?, NOW())"
);
$stmt->execute([
$data['name'],
$data['email'],
password_hash($data['password'], PASSWORD_DEFAULT)
]);
return (int)$this->pdo->lastInsertId();
}
public function update($id, array $data): bool {
$sets = [];
$values = [];
foreach ($data as $key => $value) {
$sets[] = "$key = ?";
$values[] = $value;
}
$values[] = $id;
$sql = "UPDATE users SET " . implode(', ', $sets) . " WHERE id = ?";
return $this->pdo->prepare($sql)->execute($values);
}
public function delete($id): bool {
$stmt = $this->pdo->prepare("DELETE FROM users WHERE id = ?");
return $stmt->execute([$id]);
}
}
完整项目结构建议
your-project/
├── src/
│ ├── Models/ # 数据模型(实体类,可选)
│ │ └── UserEntity.php
│ ├── Repositories/ # 仓库层(数据访问)
│ │ └── UserRepository.php
│ ├── Services/ # 业务逻辑层
│ │ └── UserService.php
│ └── Database/ # 数据库连接
│ └── Connection.php
├── config/
│ └── database.php
└── public/
└── index.php
使用第三方ORM(生产推荐)
如果项目规模较大,建议直接使用成熟的ORM:
Laravel + Eloquent
// 模型定义
class User extends Model {
protected $fillable = ['name', 'email', 'password'];
public function posts() {
return $this->hasMany(Post::class);
}
}
// 使用
$user = User::find(1);
$user->name = 'New Name';
$user->save();
MySQLi基础封装(最简方案)
class Db {
private static $instance;
private $mysqli;
private function __construct() {
$this->mysqli = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
}
public static function table($table) {
self::getInstance()->table = $table;
return self::getInstance();
}
public function find($id) {
$stmt = $this->mysqli->prepare("SELECT * FROM {$this->table} WHERE id = ?");
$stmt->bind_param("i", $id);
$stmt->execute();
return $stmt->get_result()->fetch_assoc();
}
}
关键注意事项
- SQL注入防护:永远使用预处理语句(prepare + execute)
- 连接管理:生产环境使用连接池或单例模式
- 数据验证:在模型中做基础验证,在Service层做业务验证
- 异常处理:统一封装成自定义异常类
- 性能考虑:对于复杂查询,使用查询构建器而不是纯SQL拼接
选择建议
- 项目<5万行代码:PDO封装 + Repository模式足够
- 中大型项目:使用Laravel的Eloquent或Symfony的Doctrine
- 微服务:可以考虑轻量级的Medoo或NotORM
- 追求极致性能:手写PDO + 简单的ActiveRecord模式
最重要的是保持一致性:整个团队使用同一模式,并且数据访问层与业务逻辑层充分分离。