什么是教义2中的代理?

我刚刚读完了所有的Doctrine 2文档,开始了我自己的沙箱,我了解了大部分原理,但仍然有一个问题,我找不到任何完整的解释。

  1. 什么是Proxy类?
  2. 我应该什么时候使用它们在实体上?

据我所知,代理类添加一个层,让您添加一些其他function到您的实体,但为什么使用代理,而不是在实体类中实现方法本身?

只要您的查询没有返回创build实体所需的所有数据,就会使用代理对象。 想象下面的情景:

 @Entity class User { @Column protected $id; @Column protected $username; @Column protected $firstname; @Column protected $lastname; // bunch of setters/getters here } DQL query: SELECT u.id, u.username FROM Entity\User u WHERE u.id = :id 

正如你所看到的,这个查询不返回firstnamelastname属性,所以你不能创buildUser对象。 创build不完整的实体可能会导致意外的错误。

这就是为什么Doctrine将创build支持延迟加载的UserProxy对象。 当你尝试访问firstname属性(未加载)时,它将首先从数据库加载该值。


我的意思是为什么我应该使用代理?

你应该总是写你的代码,就好像你根本没有使用代理对象。 它们可以被视为教义使用的内部对象。

为什么惰性加载不能在Entitiy中实现?

从技术上讲,它可能是,但看看一些随机代理对象的类。 这是很脏的代码,呃。 在你的实体中有一个干净的代码是很好的。

你能给我一个用例吗?

您正在显示最新的25篇文章的列表,并且想要显示第一篇文章的详细信息。 它们每个都包含大量的文本,因此获取所有这些数据会浪费内存。 这就是为什么你不要获取不必要的数据。

 SELECT a.title, a.createdAt FROM Entity\Article a ORDER BY a.createdAt DESC LIMIT 25 $isFirst = true; foreach ($articles as $article) { echo $article->getTitle(); echo $article->getCreatedAt(); if ($isFirst) { echo $article->getContent(); // Article::content is not loaded so it is transparently loaded // for this single article. $isFirst = false; } } 

UPDATE

在下面的注释部分中,有关代理对象和部分对象之间差异的错误信息。 有关更多详细信息,请参阅@Kontrollfreak答案: https ://stackoverflow.com/a/17787070/252591

代理

一个Doctrine代理只是一个包装器,它扩展了一个实体类来为它提供延迟加载。

默认情况下,当向实体pipe理器询问与另一个实体关联的实体时,关联的实体将不会从数据库中加载,而是包装到代理对象中。 当你的应用程序接着请求一个属性或者调用这个代理实体的方法时,Doctrine将从数据库中加载这个实体(当你请求这个代理总是知道的ID时除外)。

由于代理扩展了您的实体类,因此这对您的应用程序完全透明。

如果您不在查询中JOIN关联,或者将获取模式设置为EAGER Doctrine默认会将关联充作延迟加载代理。


现在我必须补充一点,因为我没有足够的声望来评论无处不在:

不幸的是,Crozin的答案包含错误的信息。

如果你像执行一个DQL查询

 SELECT u.id, u.username FROM Entity\User u WHERE u.id = :id 

你不会得到(代理)实体对象,而是一个关联数组。 所以懒得加载任何额外的属性是不可能的。

考虑到这一点,我们得出结论,用例的例子也不起作用。 为了访问$article作为对象,DQL必须改成这样的东西:

 SELECT a FROM Entity\Article a ORDER BY a.createdAt DESC LIMIT 25 

而且由getContent()返回的属性必须是一个关联,以便不加载所有 25个实体的内容属性。


部分对象

如果你想部分加载不是关联的实体属性,你必须明确地告诉这个主义:

 SELECT partial u.{id, username} FROM Entity\User u WHERE u.id = :id 

这给你一个部分加载的实体对象。

但要注意,部分对象不是代理服务器! 延迟加载不适用于他们。 因此,使用部分对象通常是危险的,应该避免。 阅读更多: 部分对象 – Doctrine 2 ORM 2文档