Ответ 1
Поскольку этот вопрос довольно старый, я думаю, вы уже пытались написать 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 в Доктрине или 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 в своем Постоянный объект в качестве формата конфигурации. То, что я использовал, тоже казалось естественным выбором, и CMS, с которым я работал, также использовал формат конфигурации PHP.
С помощью этой конфигурации вы определяете
- какая таблица сопоставляется с классом
- какие поля должны быть сопоставлены с экземпляром класса
- какой тип полей имеет таблица (int, string и т.д.)
- отношения между объектами (например, класс User имеет ссылку на класс UserGroup)
- и др.
И это информация, которую вы используете в своем Data Mapper для сопоставления результата DB с объектами.
Реализация
Я решил пойти с сильным подходом к тестированию из-за сложного характера написания пользовательской ORM. TDD или нет, написав много, много модульных тестов - действительно хорошая идея для такого проекта. Кроме того: держите руки грязными и храните книгу Фаулеров близко.;-)
Как я уже сказал, это действительно стоит усилий, но я бы не хотел делать это снова, из-за зрелых фреймворков, существующих в наши дни.
Я больше не использую свой ORM, он работал, но у него не было многих функций: ленивая загрузка, сопоставление компонентов, поддержка транзакций, кеширование, настраиваемые типы, подготовленные операторы/параметры и т.д. И это было неэффективно, t достаточно хорошо для использования в крупных проектах.
Тем не менее, я надеюсь, что могу дать вам несколько отправных точек в области ORM, если вы их не знали.; -)