草庐IT

php - 学习实现基本 ORM 的技巧/资源/模式

coder 2023-12-30 原文

关闭。这个问题需要更多focused .它目前不接受答案。












想改善这个问题吗?更新问题,使其仅关注一个问题 editing this post .

7年前关闭。



Improve this question




我在这里看到了各种 MVC 框架以及用于 PHP 的独立 ORM 框架,以及其他 ORM 问题;然而,大多数问题都要求从现有框架开始,这不是我想要的。 (我也读过 this SO question ,但我不知道该怎么做,因为答案含糊不清。)

相反,我认为通过亲自动手并实际编写自己的 ORM 来学习最好,即使是一个简单的 ORM。除了我真的不知道如何开始,特别是因为我在其他 ORM 中看到的代码非常复杂。

用我的 PHP 5.2.x(这很重要) MVC 框架我有一个基本的自定义数据库抽象层,它具有:

  • 非常简单的方法,如 connect($host, $user, $pass, $base) , query($sql, $binds)
  • 它支持的每个 DBMS 的子类
  • 表示 SQL 结果集的类(和相应的子类)

  • 但是有:
  • Active Record 功能,我认为是 ORM 的东西(如果我错了,请纠正我)

  • 编辑:澄清一下,我只有一个数据库抽象层。我还没有模型,但是当我实现它们时,我希望它们是原生 ORM 模型(可以这么说),因此这个问题。

    我已经阅读了一些关于 ORM 的内容,根据我的理解,它们提供了一种通过将数据表示为基于 PHP 的类/对象来进一步从数据库本身抽象数据模型的方法;再次,如果我错了或以任何方式错过了,请纠正我。

    不过,我想从或多或少涉足 ORM 框架的其他人那里得到一些简单的提示。还有什么我需要注意的,简单的,学术样本供我引用,或者我可以阅读的资源?

    最佳答案

    由于这个问题相当古老,我猜您已经尝试过自己编写 ORM。尽管如此,两年前我写了一个自定义 ORM,我仍然想分享我的经验和想法。

    如前所述,我两年前实现了一个自定义 ORM,甚至在中小型项目中使用它并取得了一些成功。我将它集成到一个相当流行的 CMS 中,当时(甚至现在)它缺乏这样的 ORM 功能。此外,当时,像 Doctrine 这样的流行框架并没有真正说服我。从那时起发生了很大变化,Doctrine 2在一个坚实的框架中发展,所以,如果我现在可以选择实现我自己的 ORM 或使用流行的框架之一,如 Doctrine 2 用于生产用途,这将毫无疑问 - 使用现有的稳定解决方案。但是:实现这样一个框架(以简单的方式)是一个非常有值(value)的学习练习,它对我处理更大的开源 ORM 有很大帮助,因为您可以更好地理解与对象关系映射相关的陷阱和困难。

    实现基本的 ORM 功能并不太难,但是一旦对象之间的关系映射发挥作用,它就会变得更加困难/有趣。

    我是如何开始的?

    让我着迷的是 Martin Fowlers 的书 Patterns of Enterprise Application Architecture .如果您想编写自己的 ORM,或者即使您只是在使用某个 ORM 框架,请购买这本书。它是最有值(value)的资源之一,涵盖了与对象关系映射领域有关的许多基本和高级技术。阅读它,你会得到很多关于 ORM 背后模式的好主意。

    基础架构

    我决定是否要使用 Active Record方法或某种 Data Mapper .此决定会影响数据库中的数据如何映射到实体。我决定实现一个简单的数据映射器,方法与 Doctrine 2 相同。或 Hibernate在 Java 中使用。 Active Record 是 Zend Framework 中 ORM 功能的方法(如果您可以这样称呼的话) . Active Record 比 Data Mapper 简单得多,但也受到更多限制。阅读这些模式并检查提到的框架,您会很快发现差异。如果您决定使用数据映射器,您还应该阅读 PHPs reflection API .

    查询

    我有一个雄心勃勃的目标,即创建自己的查询语言,就像 DQL 一样。在教义或 HQL在休眠中。我很快就放弃了,因为编写自定义 SQL 解析器/词法分析器似乎很复杂(而且确实如此!)。我所做的是实现一个 Query Object ,为了封装查询中涉及哪个表的信息(这很重要,因为您需要将数据从数据库映射到每个表的相关类)。

    在我的 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 在其 Persistent Object component 中使用 PHP 数组。作为配置格式。这也是我使用的,这似乎是一个自然的选择,我使用的 CMS 也使用了 PHP 配置格式。

    使用该配置,您可以定义
  • 哪个表映射到哪个类
  • 哪些字段应该映射到类实例
  • 表的字段有什么类型(整数、字符串等)
  • 实体之间的关系(例如 User 类引用了 UserGroup 类)

  • 这就是您在 Data Mapper 中用于将 DB 结果映射到对象的信息。

    实现

    由于编写自定义 ORM 的复杂性,我决定采用强大的测试驱动方法。无论是否使用 TDD,编写许多单元测试对于这样的项目来说都是一个非常好的主意。除此之外:弄脏你的手,让福勒的书靠近。 ;-)

    正如我所说,这确实值得付出努力,但我不想再做一次,这主要是因为当今存在的成熟框架。

    我不再使用我的 ORM,它可以工作,但缺少许多功能,其中包括:延迟加载、组件映射、事务支持、缓存、自定义类型、准备好的语句/参数等。而且它的性能不够好用于大型项目。

    尽管如此,我希望我能给你一些 ORM 领域的起点,如果你还不知道的话。 ;-)

    关于php - 学习实现基本 ORM 的技巧/资源/模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2887530/

    有关php - 学习实现基本 ORM 的技巧/资源/模式的更多相关文章

    1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

      我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

    2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

      我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

    3. ruby - 如何在续集中重新加载表模式? - 2

      鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

    4. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

      我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

    5. ruby - 安装 Ruby 时遇到问题(无法下载资源 "readline--patch") - 2

      当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub

    6. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

      给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

    7. ruby-on-rails - Rails 3,嵌套资源,没有路由匹配 [PUT] - 2

      我真的为这个而疯狂。我一直在搜索答案并尝试我找到的所有内容,包括相关问题和stackoverflow上的答案,但仍然无法正常工作。我正在使用嵌套资源,但无法使表单正常工作。我总是遇到错误,例如没有路线匹配[PUT]"/galleries/1/photos"表格在这里:/galleries/1/photos/1/edit路线.rbresources:galleriesdoresources:photosendresources:galleriesresources:photos照片Controller.rbdefnew@gallery=Gallery.find(params[:galle

    8. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

      华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

    9. Unity 热更新技术 | (三) Lua语言基本介绍及下载安装 - 2

      ?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------

    10. 基于C#实现简易绘图工具【100010177】 - 2

      C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

    随机推荐