PHP, Архитектуры, Технологии → ORM и с чем его едят
ORM — это аббревиатура от Object Relational Mapping (по русски — Объектно-реляционная проекция).
Конечно же, ORM — это технология. А с другой стороны — это слой приложения. И инструмент RAD (Rapid Application Development — Быстрой разработки приложений). А еще — это детище объектно-ориентированного подхода создания приложений.
Суть проблемы, которая решается с помощью ORM-слоя, заключается в необходимости преобразования объектных структур в памяти приложения в форму, удобную для сохранения в реляционных базах данных (и не только), а также для решения обратной задачи — развертывания реляционной модели в объектную, с сохранением свойств объектов и отношений между ними.
На простом примере, мы можем рассмотреть, например, базу музыкальных композиций, которая может храниться на вашем домашнем компьютере или удаленном сервере. Давайте нарисуем ее реляционную структуру.

Рис 1. Схема реляционной структуры данных
Как видим, схема достаточно проста. У нас есть 3 сущности — Исполнитель (artist), Альбом (album) и Песня (song). При этом, у каждого исполнителя, есть 0 или больше альбомов, в каждый из которых входит 0 или больше песен.
В нашей же программе, мы также можем манипулировать, как минимум, тремя типами объектов — Исполнитель, Альбом и Песня, каждый из которых будет воплощением записи в соответствующей таблице базы данных. Помимо этого, нам, очевидно, понадобятся коллекции объектов записей (Record Sets) и шлюзы к таблицам данных (Table Data Gateways).
Следует отметить, что три наших основных объекта (Исполнитель, Альбом и Песня), в данном случае, выступают постоянными объектами (Persistent Objects), так как их время жизни не ограничено временем действия создавшей их программы (фактически они используют для хранения своего состояния СУБД, а значит всегда могут быть извлечены из нее в том виде, в котором были сохранены).
Безусловно, существует несколько способов отображения постоянных объектов. Например, — активная запись (Active Record) или шлюз записи данных (Row Data Gateway).
Т.е., мы можем представить наш программный слой, упрощенно, примерно следующим образом.

Рис. 2. Модель классов программы
Из приведенной схемы можно сделать несколько выводов.
- Классы Artist, Album, Song могут быть наследниками одного родителя, который реализует __set () и __get () методы, для доступа к свойствам объекта, а также будет производить автоматическую валидацию принимаемых аргументов через установленный интерфейс.
- Методы save () и delete () также могут быть унифицированы и реализованы в классе-родителе. Отнюдь не лишним будет реализовать в нем, например, и обработку событий onInsert, onUpdate, onDelete и т.п.
- Задача по унификации и абстрагированию классов таблиц также может быть успешно решена через наследование, а приведенные классы могут существовать исключительно для реализации специфических функций, связанных непосредственно с решением каждой, отдельно поставленной задачей.
А если позаботиться ещё и о различных слоях доступа к разным СУБД (MySQL, MSSQL, Oracle, PostgreSQL), уже становится очевидным тот факт, что все это тянет на постановку довольно обширной универсальной задачи построения типового решения проекции объектов в реляционные структуры и наоборот.
На сегодняшний день для большинства языков программирования разработаны как коммерческие, так и бесплатные решения. Многие из них, помимо пакетов с абстрактными классами ORM-слоя, имеют и инструменты автоматической генерации кода классов шлюзов таблиц и постоянных объектов, обладают мощной функциональностью и гибкостью, позволяя решать задачи несколькими способами.
С развитием языка PHP до версии 5, в котором модель ООП достигла новых высот, необходимость в наличии ORM-слоя возросла.
На сегодняшний день можно назвать несколько отличных бесплатных решений для PHP 5 — Propel, Doctrine и пакет Zend_Db из поставки Zend Framework.
У каждой из них есть свои достоинства и недостатки, в конце-концов, есть и субъективные предпочтения разработчиков. И если первые два — это полноценные слои с широкими возможностями (генерация кода, YAML-конфигурирование и т.д.), то Zend_Db на их фоне остается всего лишь пакетом, требующим достаточно много ручной работы. Единственный его плюс в том, что он уже является частью зендовского MVC.
Надеюсь каждый разработчик сам сможет выбрать и использовать подходящее для него решение.
Удачи в девелопменте!

23:05:31
Zend FrameWork больше как библиотека позиционируется.
08:06:42
> Zend FrameWork больше как библиотека позиционируется.
А это вы к чему сказали?
04:08:45
неплоха бы пару примеров показать из Propel или Doctrine
08:20:43
> неплоха бы пару примеров показать из Propel или Doctrine
Просто не хотелось привязываться ни к какой конкретной реализации, хотя пару примеров конечно можно...
17:47:09
Хорошая, грамотная статья. С удовольствием прочитал. Но заканчивается довольно неожиданно. Хотелось бы увидеть несколько примеров, а также небольшое сравнение Propel и Doctrine, чтоб легче было определиться с выбором.
19:32:01
Doctrine конечно штука очень хорошая в плане того, что очень облегчает разработку, я с ней год проработал, но есть одно большое НО — она жутко медленно работает, т.к. там с ООП перемудрили.
Сейчас потихоньку перебираюсь на Zend_Db, очень не хочется, но других альтернатив я не нашёл ((
Всё-таки скорость для высоконагрузных сайтов важнее, чем скорость разработки )
Doctrine лучше всего в админке использовать ну или в каких то сложных интерфейсах.
16:12:19
Да, если вы будете постоянно обрабатывать большие коллекции объектов — их маппинг занимает много времени. Тем не менее она очень просто оптимизируется и скорость работы весьма и весьма. Единственное неудобство — приходится каждый раз задумываться — в данном случае нужны мне объекты или нет.
Тем не менее она очень удачно мапит данные в обычные РНР-массивы со структурой идентичной объектной модели. Поэтому, если в представлениях пользоваться удобствами, которые предоставляет интерфейс ArrayAccess (а доктриновская коллекция его реализует), то оптимизировать работу становиться несказанно просто — нужно лишь изменить hydration mode с объектов на массивы. Скорость взлетает в сотни раз на отдельных участках кода.
И, в свою очередь, когда нужно как раз работать именно с объектом, то у вас все в руках. У меня лично просто выработалось правило — если меняю или создаю один или пару объектов — все удобно в объектном виде, а для отображения большого списка — запрещаю маппинг в объекты. Хуже, когда нужно целиком изменить коллекцию. Здесь на помощь приходит построение собственных сложных запросов. Тем не менее логика все-равно остается зашитой в самой модели, поэтому снаружи это не выглядит как проблема и скорость очень даже приличная, сравнимая с обычным скриптом.
11:41:11
[...] можно почитать: • ORM и с чем его едят • Шаблон DataMapper • List of object-relational mapping software: PHP • [...]