07. Создание класса Database и модели данных
Введение
В предыдущих уроках мы напрямую использовали PDO в каждом файле. Это удобно для начала, но когда проект растёт, код подключения к БД повторяется десятки раз.Чтобы не дублировать и структурировать код, создадим отдельный класс Database, который будет отвечать за все операции с базой. А для каждой таблицы сделаем отдельную модель.
Инкапсуляция — это когда мы прячем внутренние детали и оставляем только удобный интерфейс для работы.
Проблема без инкапсуляции
Посмотрим на код без класса:
$pdo = new PDO('mysql:host=localhost;dbname=my_app','root','');
$stmt = $pdo->prepare('SELECT * FROM users');
$stmt->execute();
$users = $stmt->fetchAll();
Такой код быстро засоряет проект. Если завтра изменится имя базы или пароль — придётся править везде. Решение — спрятать подключение в класс.Создаём класс Database
<?php
class Database {
private $pdo; // подключение к базеpublic function __construct($dbname = 'my_app', $host = 'localhost', $user = 'root', $pass = '') {
$dsn = "mysql:host=$host;dbname=$dbname;charset=utf8mb4";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
];
$this->pdo = new PDO($dsn, $user, $pass, $options);
}
public function query($sql, $params = []) {
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt;
}
}
?>
Разбор кода
- private $pdo — свойство, где хранится подключение к базе.
- __construct() — выполняется при создании объекта и сразу подключается к MySQL.
- query() — универсальный метод для выполнения SQL-запросов.
Теперь подключение выполняется один раз, и мы можем использовать этот класс везде.
Использование класса
<?php
require 'Database.php';$db = new Database();
$users = $db->query('SELECT * FROM users')->fetchAll();
foreach ($users as $u) {
echo $u['name'] . ' — ' . $u['email'] . '<br>';
}
?>
Создание модели данных
Каждая таблица в базе обычно представляется в коде отдельным классом-моделью. Например, таблица users — класс UserModel.
<?php
require 'Database.php';class UserModel extends Database {
public function getAll() {
return $this->query('SELECT * FROM users')->fetchAll();
}
public function findById($id) {
return $this->query('SELECT * FROM users WHERE id = ?', [$id])->fetch();
}
public function create($name, $email, $password) {
$hash = password_hash($password, PASSWORD_DEFAULT);
$this->query('INSERT INTO users (name,email,password) VALUES (?,?,?)', [$name, $email, $hash]);
}
public function delete($id) {
$this->query('DELETE FROM users WHERE id = ?', [$id]);
}
}
?>
Разбор методов модели
- getAll() — возвращает всех пользователей
- findById() — ищет пользователя по ID
- create() — добавляет нового пользователя
- delete() — удаляет пользователя из таблицы
Проверим работу модели
<?php
require 'UserModel.php';$userModel = new UserModel();
// Добавим нового пользователя
$userModel->create('Константин', 'konst@mail.com', '12345');
// Выведем всех пользователей
$users = $userModel->getAll();
foreach ($users as $u) {
echo '<p>' . htmlspecialchars($u['name']) . ' (' . htmlspecialchars($u['email']) . ')</p>';
}
?>
Инкапсуляция и наследование
Мы наследуем UserModel от Database, чтобы не повторять код подключения. Это пример повторного использования (реюза) логики.Если потом появится ArticleModel или OrderModel, они смогут работать с базой точно так же.
Добавляем универсальный метод insert/update
Можно улучшить класс Database, добавив общие методы.
class Database {
private $pdo;
public function __construct() {
$this->pdo = new PDO('mysql:host=localhost;dbname=my_app','root','');
}public function insert($table, $data) {
$keys = array_keys($data);
$fields = implode(',', $keys);
$placeholders = implode(',', array_fill(0, count($data), '?'));
$sql = "INSERT INTO $table ($fields) VALUES ($placeholders)";
$this->query($sql, array_values($data));
}
}
$db = new Database();
$db->insert('users', [
'name' => 'Иван',
'email' => 'ivan@example.com',
'password' => password_hash('12345', PASSWORD_DEFAULT)
]);
Что это даёт
Теперь можно вставлять данные в любую таблицу одной строкой — не нужно вручную писать SQL каждый раз.Мини-проект: список пользователей
Создадим страницу users.php, которая покажет всех пользователей в виде таблицы.
<!doctype html>
<html lang='ru'>
<head>
<meta charset='utf-8'>
<title>Пользователи</title>
</head>
<body>
<h2>Список пользователей</h2>
<?php
require 'UserModel.php';
$userModel = new UserModel();
$users = $userModel->getAll();
?>
<table border='1' cellpadding='6'>
<tr><th>ID</th><th>Имя</th><th>Email</th><th>Дата регистрации</th></tr>
<?php foreach ($users as $u): ?>
<tr>
<td><?= htmlspecialchars($u['id']) ?></td>
<td><?= htmlspecialchars($u['name']) ?></td>
<td><?= htmlspecialchars($u['email']) ?></td>
<td><?= htmlspecialchars($u['created_at']) ?></td>
</tr>
<?php endforeach; ?>
</table>
</body>
</html>
Преимущества подхода с классом Database
- Код становится структурированным и легко поддерживаемым
- Изменить подключение можно в одном месте
- Методы query, insert, fetch можно многократно переиспользовать
- Модели (UserModel, ArticleModel и др.) делают проект масштабируемым
Итоги урока
Вы узнали:- Как создать класс Database для подключения и запросов
- Как инкапсулировать логику PDO в одном месте
- Как создать модель UserModel и работать с ней
- Как использовать методы для добавления, поиска и удаления данных
- Как построить мини-систему управления пользователями на PHP + ООП