Советы / ресурсы / шаблоны для обучения внедрению базового ORM

Я видел различные рамки MVC, а также автономные рамки ORM для PHP, а также другие вопросы ORM. тем не менее, большинство вопросов требуют начала существующих фреймворков, чего я не ищу. (Я также прочитал этот вопрос , но я не уверен, что с ним делать, поскольку ответы расплывчаты.)

Вместо этого я решил, что лучше всего научусь, когда мои руки станут грязными и на самом деле напишу свой собственный ORM, даже простой. Кроме того, я не знаю, как начать, тем более что код, который я вижу в других ORM, настолько сложный.

С моим PHP 5.2.x (это важно) MVC framework У меня есть базовый уровень абстракции базы данных, который имеет:

  • Очень простые методы, такие как connect($host, $user, $pass, $base) , query($sql, $binds) и т. Д.
  • Подклассы для каждой СУБД, которые она поддерживает
  • Класс (и соответствующие подклассы) для представления наборов результатов SQL

Но не имеет:

  • Функция Active Record, которую я предполагаю, является ORM (поправьте меня, если я ошибаюсь)

EDIT: уточнить, у меня есть только уровень абстракции базы данных. У меня пока нет моделей, но когда я их реализую, я хочу, чтобы они были родными ORM-моделями (так сказать), следовательно, этот вопрос.

Я немного ознакомился с ORM, и, насколько я понимаю, они предоставляют средства для дальнейшей абстрактной модели данных из самой базы данных, представляя данные как не что иное, как классы / объекты на основе PHP; снова, исправьте меня, если я ошибаюсь или что-то пропустил.

Тем не менее, я хотел бы получить несколько простых советов от кого-либо еще, кто больше или меньше использовал рамки ORM. Есть ли что-нибудь еще, что мне нужно принять к сведению, простые, академические образцы, на которые я могу ссылаться, или ресурсы, которые я могу прочитать?

Поскольку этот вопрос довольно старый, я думаю, вы уже пытались написать ORM самостоятельно. Тем не менее, поскольку я написал обычную ORM два года назад, я все равно хотел бы поделиться своим опытом и идеями.

Как сказал, я реализовал обычную ORM два года назад и даже использовал ее с некоторым успехом в проектах малого и среднего размера. Я включил его в довольно популярную CMS, которая в то время (и даже сейчас) не обладает такой функциональностью ORM. Кроме того, в то время популярные структуры, такие как Doctrine, не меня действительно убедили. С тех пор многое изменилось, и Doctrine 2 эволюционировала в прочной структуре, поэтому, если бы у меня теперь был выбор между реализацией моей собственной ORM или использованием одной из популярных фреймворков, таких как Doctrine 2 для использования в производстве, это было бы бесспорным – используйте существующие, стабильные решения. НО: внедрение такой структуры (простым способом) было очень ценным учебным упражнением, и это помогло мне много работать с большими ORM с открытым исходным кодом, так как вы лучше понимаете подводные камни и трудности, связанные с реляционным сопоставлением объектов.

Не сложно реализовать базовые функциональные возможности ORM, но как только отображение отношений между объектами вступит в игру, становится намного сложнее и интереснее.

Как я начал?

То, что меня зацепило, – это книга Мартина Фаулерса « Модели корпоративного архитектуры приложений» . Если вы хотите запрограммировать свой собственный ORM или даже если вы просто работаете с какой-либо структурой ORM, купите эту книгу. Это один из самых ценных ресурсов, который охватывает многие базовые и передовые методы в области реляционного сопоставления объектов. Прочитайте это, вы получите много замечательных идей о шаблонах, стоящих за ORM.

Основная архитектура

Я решил, хотел ли я использовать подход Active Record или какой-то Data Mapper . Это решение влияет на то, как данные из базы данных сопоставляются с сущностью. Я решил реализовать простой Data Mapper, тот же подход, что и Doctrine 2 или Hibernate в Java. Active Record – это подход функциональности ORM (если можно так выразиться ) в Zend Framework . Активная запись намного проще, чем Data Mapper, но также гораздо более ограничена. Прочитайте эти шаблоны и проверьте упомянутые структуры, вы получите разницу довольно быстро. Если вы решите пойти с Data Mapper, вы также должны ознакомиться с API отражения PHP .

Запрос

У меня была амбициозная цель – создать собственный язык запросов, как DQL в Doctrine или HQL в Hibernate. Вскоре я отказался от этого, так как написание пользовательского анализатора SQL / lexer казалось сложным (и это действительно так!). То, что я сделал, это реализовать объект запроса , чтобы инкапсулировать информацию, в которую вовлечена эта таблица (что важно, поскольку вам необходимо сопоставить данные из базы данных с соответствующими классами для каждой таблицы).

Запрос объекта в моем ORM выглядел следующим образом:

 public function findCountryByUid($countryUid) { $queryObject = new QueryObject(); $queryObject->addSelectFields(new SelectFields('countries', '*')) ->addTable(new Table('countries')) ->addWhere('countries.uid = "' . intval($countryUid) . '"'); $res = $this->findByQuery($queryObject); return $res->getSingleResult(); } 

конфигурация

Как правило, вам также нужно иметь какой-то конфигурационный формат, Hibernate использует XML (среди прочих), Doctrine 2 использует аннотации PHP, EZComponents использует массивы PHP в своем компоненте Persistent Object в качестве конфигурационного формата. То, что я использовал, тоже казалось естественным выбором, и CMS, с которым я работал, также использовал формат конфигурации PHP.

С этой конфигурацией вы определяете

  • какая таблица сопоставляется с каким классом
  • какие поля должны быть сопоставлены с экземпляром класса
  • какой тип полей таблицы имеет (int, string и т. д.),
  • отношения между объектами (например, класс User имеет ссылку на класс UserGroup)
  • и т.п.

И это информация, которую вы используете в своем Data Mapper для сопоставления результата DB с объектами.

Реализация

Я решил пойти с сильным подходом к тестированию из-за сложного характера написания пользовательской ORM. TDD или нет, написав много, много модульных тестов – действительно хорошая идея для такого проекта. Кроме того: держите руки грязными и храните книгу Фаулеров близко. 😉


Поскольку я сказал, что это действительно стоило усилий, но я бы не хотел этого делать снова, из-за зрелых фреймворков, которые существуют в наши дни.

Я больше не использую свой ORM, это сработало, но не хватало многих функций: ленивая загрузка, сопоставление компонентов, поддержка транзакций, кеширование, пользовательские типы, подготовленные операторы / параметры и т. Д. И это было не так хорошо для использования в крупных проектах.

Тем не менее, я надеюсь, что могу дать вам несколько отправных точек в области ORM, если вы их не знали. 😉

Простую ORM можно построить с помощью __get() и __set() и нескольких настраиваемых методов (возможно, используя __call() ), вот простой псевдокод:

 class ORM { private $table = null; private $fields = array(); function __construct($table) { $this->table = $table; } function __get($key) { return isset($this->fields[$key]) ? $this->fields[$key] : false; } function __set($key, $value) { $this->fields[$key] = $value; } function load($id, $field = 'id') { // populate $this->fields with SELECT * FROM $this->table WHERE $field = $id; } function save() { if (isset($this->fields['id'])) { // UPDATE $this->table SET $this->fields; } else { // INSERT INTO $this->table $this->fields; } } } $user = new ORM('user'); $user->name = 'name'; $user->pass = '1337'; $user->save(); 

Это просто базовый пример, чтобы вы начали. Вы можете добавить дополнительную логику с помощью __call() magic для получения результатов другими полями, кроме, например, id .

Имейте в виду, что пример, который я дал, не обрабатывает отношения, поэтому различные реализации ORM действительно различаются, однако я обычно не доверяю ORM для обработки отношений для меня, поскольку они имеют тенденцию быть более медленными и не создают эффективных запросов.