ORM для PHP: сравнение Doctrine, Eloquent и Propel с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

ORM для PHP: сравнение Doctrine, Eloquent и Propel

Объектно-реляционное отображение (ORM) — это технология, которая позволяет разработчикам работать с базами данных, используя объектно-ориентированный подход вместо написания чистых SQL-запросов. Для PHP существует несколько зрелых ORM-решений, каждое из которых имеет свои сильные стороны. В этой статье мы подробно сравним три наиболее популярных ORM: Doctrine, Eloquent (из Laravel) и Propel, а также приведём практические примеры кода.

1. Doctrine: мощный DataMapper

Doctrine — это, пожалуй, самый зрелый и функциональный ORM для PHP. Он реализует паттерн DataMapper, что означает полное разделение бизнес-логики и логики работы с БД. Основные характеристики:

  • Поддержка множества СУБД (MySQL, PostgreSQL, SQLite, Oracle, MSSQL)
  • Гибкая система запросов через DQL (Doctrine Query Language)
  • Встроенная поддержка миграций, событий, прокси-объектов (ленивая загрузка)
  • Высокая производительность при правильной настройке кэширования

Пример: определение сущности и запрос

// Сущность User
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
#[ORM\Table(name: "users")]
class User
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: "integer")]
    private int $id;

    #[ORM\Column(type: "string", length: 100)]
    private string $name;

    #[ORM\Column(type: "string", length: 255, unique: true)]
    private string $email;

    // Геттеры и сеттеры
    public function getId(): int { return $this->id; }
    public function getName(): string { return $this->name; }
    public function setName(string $name): void { $this->name = $name; }
    public function getEmail(): string { return $this->email; }
    public function setEmail(string $email): void { $this->email = $email; }
}

// Запрос через EntityManager
$userRepository = $entityManager->getRepository(User::class);
$users = $userRepository->findBy(['name' => 'Иван'], ['id' => 'DESC'], 10);
foreach ($users as $user) {
    echo $user->getName() . ' - ' . $user->getEmail() . PHP_EOL;
}

2. Eloquent: простота и элегантность

Eloquent — стандартный ORM фреймворка Laravel, реализующий паттерн ActiveRecord. Каждая модель является одновременно и сущностью, и репозиторием. Главные плюсы:

  • Минимальный код для стандартных операций
  • Красивый fluent-интерфейс построения запросов
  • Встроенные отношения (belongsTo, hasMany, morphMany и т.д.)
  • Отличная документация и огромное сообщество

Пример: модель и запросы

// Модель User (файл app/Models/User.php)
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    protected $fillable = ['name', 'email'];
    
    // Определение отношения "один ко многим"
    public function posts()
    {
        return $this->hasMany(Post::class);
    }
}

// Использование в контроллере
$users = User::where('name', 'LIKE', '%Иван%')
             ->orderBy('created_at', 'desc')
             ->limit(10)
             ->get();

foreach ($users as $user) {
    echo $user->name . ' - ' . $user->email . PHP_EOL;
    // Ленивая загрузка связанных записей
    foreach ($user->posts as $post) {
        echo '  Пост: ' . $post->title . PHP_EOL;
    }
}

3. Propel: производительность и генерация кода

Propel — это ORM, который генерирует классы на основе схемы базы данных (XML или YAML). Он использует паттерн ActiveRecord, но с акцентом на производительность и строгую типизацию. Ключевые особенности:

  • Генерация классов моделей (нет необходимости писать геттеры/сеттеры вручную)
  • Встроенная поддержка i18n, вложенных множеств, деревьев
  • Высокая скорость за счёт генерации оптимального SQL
  • Хорошая интеграция с Symfony (но можно использовать и отдельно)

Пример: схема и использование

<?xml version="1.0" encoding="UTF-8"?>
<database name="default" namespace="Models">
    <table name="users" phpName="User">
        <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true"/>
        <column name="name" type="varchar" size="100" required                    

Рекомендаций