【问题标题】:Correct class design for a web project in PHP [closed]PHP中Web项目的正确类设计[关闭]
【发布时间】:2014-11-11 18:18:57
【问题描述】:

我们正在用 OOP 重写我们的代码,我正在尝试为未来的项目设计一个通用框架(主要是为了遵守 DRY 并保持代码精简和一致)。

例如,我认为有一个基类DatabaseObject 会很好,它将从数据库行中获取其属性。它会(除其他外)使用__call()property_exists() 来自动化大多数吸气剂。这样一来,我们就不必为数据库行中的每一列潜在地编写所有 100 多个 getter(或在每次更改表时更新类代码)。

CustomerCarArticle 等其他类将扩展 DatabaseObject(如果它们来自数据库)并继承这些方法,因此我们不必将特定于数据库的代码复制到每个班级都是分开的(随着时间的推移,这会变得越来越不一致)。

这是在 Web 项目中正确使用继承的方式,还是这种糟糕的设计?我的同事争辩说,这在某种程度上是对继承的滥用,从 CSV 文件获取的客户需要单独的类定义,这是一个有效的观点。

使用接口,我们仍然需要将代码复制到每个类中,并且特征(除了需要 PHP 5.4)不适用于我上面的 __call() 示例(我认为)。

那么有没有更好的方法来实现我的DatabaseObject 概念?

编辑:有人可以向我解释拒绝投票的原因,以便我可以删除并以适当的方式重新提交我的问题吗?

【问题讨论】:

  • 自动化 getter 将导致缺少自动完成功能。您至少需要在子类中用@method 注释它们。制作一些代码生成工具,在从数据库中提取信息的同时创建带有注释的实体。您可以查看一些依赖此策略的现代 ORM。
  • @sjagr 感谢您的回复。我们实际上已经符合 PSR。但据我所知,它不涉及这样的细节。
  • 为什么不使用 ORM,比如 Doctrine 2?您仍然可以为您的实体(数据库对象)、所有实体的通用行为,甚至不对应于数据库表的对象使用基础数据类

标签: php oop inheritance


【解决方案1】:

您正在正确地将数据库表映射到对象。实际上,在你之前的人已经发明了轮子。 PHP中有几个ORM可以为您完成这项工作,而无需重新发明轮子 - 例如。教义,推动...

但是,您在当前架构中可能遇到的问题是对象的状态。如果围绕它的所有逻辑都处于抽象状态,您的实体 - CarArticle 将很难保持其状态。您需要一个映射到表列的属性,以保持对象的更改,但未提交更改。并且仅在例如调用save() 方法,提交更改。

另外,如果您需要一个额外的逻辑,比如说,您需要验证文章作者的姓名,您需要将 setAuthor() 方法物理地写在任何地方,以便对其进行更改。

我提到的 ORM 使用代码生成工具解决了这些问题,该工具检查 DB 模式并使用实体中的物理 getter 和 setter 创建类。例如,Propel 使用表名创建一个类,其中包含所有 getter 和 setter 以及那里的逻辑,但还在公共目录中创建一个扩展它的类,因此当您实例化 Article 时,您实例化了空的扩展ArticleBase 的类。 ArticleBase 确实有 setAuthor() 对作者执行更改的方法,例如更新/插入。但是,当您需要在 setAuthor() 中执行其他逻辑时,您只需在 Article 中覆盖它,执行您的逻辑并调用 parent::setArticle()

这也解决了自动完成的问题。现代开发者世界让我过分依赖自动完成。我不能也不会记得我正在使用的每个模块的公共 API,也不记得应用程序下的整个数据库。所以也许我不知道你的articles 表是否有作者的user_id 列,或者author_id。因此,我希望写$article-> 来建议我可以使用的方法。您使用__call() 的方案将导致缺少自动完成建议,因为不会生成任何方法,也不会生成任何注释。

【讨论】:

  • 谢谢,虽然我认为你误解了我的问题(或者我猜你的答案)。我的问题不在于我的DatabaseObject 及其功能,这只是一个例子。我的问题是 a)如果我对继承的使用是可以接受的还是被滥用(我一直被告知这是滥用,并且客户不是某些数据库对象的子对象等)和 b)我将如何从其他来源(如 CSV)加载客户或 XML,当我的客户类专门用于扩展数据库特定类(无论是否为 ORM)时。 ORM 有点过头了,在我的时间范围内是不可能的。
  • 如果你的所有对象都有共同点,那么继承就不会被滥用。您可以再引入一层抽象。您的所有实体都是 Entity 类的子级,可以说,它有一个 save() 抽象方法。然后,您还有两个抽象类子 Entity -> CsvObject 实现 save() 并在 .csv 文件上执行保存。而DatabaseObject 实现save() 并执行update/insert。如果您的实体没有共同点,您可以丢弃继承而只创建独立类。我个人更喜欢第一个
  • 然后从数据库切换到 Csv 只需将 Customer extends DatabaseObject 更改为 Customer extends CsvObject
  • 好吧,也许我只是在这里很密集,但这在一个项目中是行不通的,对吧?命名一个 CustomerCsv 和 CustomerDatabase 会起作用,但这会破坏这一点。继续我的(尽管很糟糕,正如你所解释的)自动吸气剂示例:我想到了 Customer extends AutoGetters implements DatabaseObjectCustomer extends AutoGetters implements CsvObject。但是扩展AutoGetters 之类的内容确实是错误的,显然不是您的意思。我觉得我完全不在这里。我真的只是不想将基本功能复制粘贴到每个需要它的类中。
  • 本质上我需要多重继承,但我知道 PHP 没有。这里通常的答案是:重新考虑你的班级设计。但我只是不知道我哪里错了。我最终不得不复制粘贴基本功能并完全违背 DRY。
猜你喜欢
  • 2010-11-04
  • 1970-01-01
  • 2014-11-30
  • 2011-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-22
  • 2011-06-29
相关资源
最近更新 更多