【问题标题】:How can public fields "break lazy loading" in Doctrine 2?Doctrine 2 中的公共字段如何“打破延迟加载”?
【发布时间】:2010-11-03 18:59:35
【问题描述】:

当我运行doctrine orm:validate-schema 时,它会弹出一堆关于我的映射列是公开的并且没有使用getter/setter 方法来包装它们的警告。它说他们“打破延迟加载”。我可以理解将 关联集合 公开可能会有问题(我确实将它们设为私有并包装它们),但这对于对象上的字段来说是个问题吗?据我所知,字段已全部加载。

【问题讨论】:

  • 老实说,我也不敢相信,直到我意识到:Doctrine 是一个 Java 库。如果他们专注于尽可能最好地使用 PHP 惯用语,而不是强迫您采用另一种语言设计的“最佳实践”,那么性能可能不会那么糟糕。我原则上同意 getter 和 setter 的论点,但在他们所做的只是代理公共字段的解释性语言中,它们是不必要的资源浪费。
  • @Shabbyrobe:谢谢。你基本上已经说出了我一直以来的想法。 Doctrine 基本上是 Hibernate 的克隆。 PHP 需要的是更多是 Active Record 的克隆。
  • Doctrine 2 和 Hibernate 都是平台无关数据映射器模式的实现,但我认为 Doctrine 2 实现它的方式使用了太多的 Java 习惯用法,例如“绝对一切的 getter 和 setter,没有问题问”。 PHP 是一种解释型语言 - 为什么要添加在对性能有可衡量的负面影响时基本上什么都不做的方法?我已经概述了我反对“一切事物的获取者和设置者”立场here的一些论点。
  • 如果您正在使用 PHP 实现活动记录,您可以尝试this。我个人更喜欢数据映射器模式而不是活动记录,但我更愿意使用用惯用 PHP 编写的活动记录库,而不是用惯用 Java 伪装成 PHP 编写的数据映射器库,所以我要看看这个库下午。
  • 如果你想要一个具有活动记录模式的 ORM,只需使用 Doctrine1 或 Propel。

标签: php doctrine-orm


【解决方案1】:

尽管我肯定不是 Doctrine2 专家,但我会试一试。

从我的(有限的)使用和测试看来,Doctrine 可能会给你一个相关的对象而不加载该对象的数据。届时公共属性将中断延迟加载。

Doctrine 在请求持久化数据时延迟加载,而不是在请求包含持久化数据的对象时。

更新:我看了一下actual proxy code,看来我最初的理解大部分是正确的。在调用对象的方法之前,代理对象不会加载自己。因此,任何对公共属性的请求都不会加载数据。

【讨论】:

  • 是的,这与代理的调用方式有关。
  • 天哪,这很烦人。感谢您的研究。
  • @ryeguy 也许,但似乎比一些替代方法更好。如果在请求持久对象时(而不是在使用时)实现延迟加载,ORM 必须以某种方式将代码放在包含相关对象的属性和可能尝试使用该对象的任何代码之间属性(包括实体对象本身)。这将使延迟加载变得不那么透明。
  • 您可以通过简单地调用来验证它是否不起作用: $entity = $em->getReference('EntityName');回声 $entity->publicField;它总是返回 NULL。
  • 感谢您的出色回答 - 帮助我解决了这个问题。有一个section in their docs 概述了他们对此“功能”的“基本原理”,并近距离显示了答案中提到的一些代理代码。摘要:答案很划算。
【解决方案2】:

请注意,现在的 Doctrine 2.4 supports proxy objects for entites with public properties

Marco Pivetta的网站解释how it works

class Customer {
    public $name;
    public $surname;
}

class CustomerProxy extends Customer {
    public function __construct(Customer $customer) {
        unset($this->name, $this->surname);
        $this->customer = $customer;
    }
    public function __set($name, $value) {
        $this->customer->$name = $value;
    }

    public function __get($name) {
        return $this->customer->$name;
    }
    // __isset, __unset, __clone, __sleep, __wakeup (or serialize/unserialize)
}

【讨论】:

  • 那么这是否意味着我们可以忽略vendor/bin/doctrine orm:validate-schema 抱怨公共财产?
  • @ErikvanVelzen 我想是的,我不知道这个工具抱怨公共属性,也许你应该提出一个问题,要求删除这个过时的功能!
  • @ErikvanVelzen 您可以简单地将您的属性设置为protected,由于__get__set 的神奇方法,它们仍然可以访问,就好像它们是公开的一样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-05-25
  • 2017-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-07
相关资源
最近更新 更多