116

I just finished reading all the Doctrine 2 documentation, I started my own sandbox, I understood most of the principes, but there is still a question and I couldn't find any complete explanation in the doc.

  1. What are Proxy classes?
  2. When should I use them over entities?

As far as I understand, proxy classes add a layer to let you add some other features to your entities, but why use a proxy instead of implementing the methods themselves in the entity class?

Jérémy
  • 1,161
  • 2
  • 8
  • 3

2 Answers2

159

UPDATE

This answer contains wrong information about differences between proxy objects and partial objects. See @Kontrollfreak's answer for more details: https://stackoverflow.com/a/17787070/252591


Proxy objects are used whenever your query doesn't return all data required to create an entity. Imagine following scenario:

@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

As you can see this query doesn't return firstname and lastname properties, therefore you cannot create User object. Creation of incomplete entity could lead to unexpected errors.

That's why Doctrine will create UserProxy object that supports lazy loading. When you'll try to access firstname property (which is not loaded) it will first load that value from database.


I mean why should I use a proxy ?

You should always write your code as if you didn't use proxy objects at all. They can be treated as internal objects used by Doctrine.

Why the lazy loading can't be implemented in the Entitiy itself?

Technically it could be but take a look at some random proxy object's class. It's full of dirty code, ugh. It's nice to have a clean code in your entities.

Can you provide me an use case?

You're displaying a list of latest 25 articles and you want to display a details of the first one. Each of them contain a large amount of text, so fetching all that data would be a waste of memory. That's why you don't fetch unnecessary data.

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;
    }
}
Samuel Katz
  • 24,066
  • 8
  • 71
  • 57
Crozin
  • 43,890
  • 13
  • 88
  • 135
  • Thank you for your answer, in what it's different with Partial Object? I mean why should I use a proxy ? Why the lazy loading can't be implemented in the Entitiy itself ? Can you provide me an use case? – Jérémy Feb 08 '11 at 17:17
  • 1
    Partial objects and proxy objects are the same thing - they can be treated as synonyms. As for the rest of questions check my updated answer. – Crozin Feb 08 '11 at 17:39
  • Thanks a lot for your answer, it's almost clear now! In fact, I don't have to edit Proxy classes unless I want to change the lazy-loading behavior or something like that. – Jérémy Feb 08 '11 at 18:01
  • 1
    I don't understand why doctrine can't create the object if it only has half of the properties. In php i am able to create an object even if i don't set all properties. – sanders Jul 20 '11 at 11:44
  • 1
    This is a totally awesome answer and should be in the documentation. – Jimbo Aug 06 '13 at 10:01
  • agree with you @Jimbo – S.Thiongane Oct 25 '13 at 15:03
  • 7
    This answer contains some serious misconceptions of proxies and partial objects. See [my answer](http://stackoverflow.com/questions/4923817/what-is-a-proxy-in-doctrine-2/17787070#17787070) to understand why. – Kontrollfreak Oct 27 '13 at 12:51
  • The problem with this example is it seems pretty pointless to me, If you are making a round trip to the database, is it not simpler just to get the whole entity? The confusion is how do you lazy load a different entity which Is a child, so one article has many article comments, and if I want to load all the comments as a collection which belong to that article, I would need another query/result set anyway right? As a join would not apply here without tons of redundant data, I am finding it very hard to understand the "magic" under the hood here –  May 20 '20 at 21:41
91

Proxies

A Doctrine proxy is just a wrapper that extends an entity class to provide Lazy Loading for it.

By default, when you ask the Entity Manager for an entity that is associated with another entity, the associated entity won't be loaded from the database, but wrapped into a proxy object. When your application then requests a property or calls a method of this proxied entity, Doctrine will load the entity from the database (except when you request the ID, which is always known to the proxy).

This happens fully transparent to your application due to the fact that the proxy extends your entity class.

Doctrine will by default hydrate associations as lazy load proxies if you don't JOIN them in your query or set the fetch mode to EAGER.


Now I must add this because I don't have enough reputation to comment everywhere:

Unfortunately, Crozin's answer contains misinformation.

If you execute a DQL query like

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

you won't get a (proxied) entity object, but an associative array. So it's not possible to lazy load any additional properties.

With this in mind, one comes to the conclusion that the use case example won't work either. The DQL would have to be changed to something like this in order to access $article as object:

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

And the property returned by getContent() would have to be an association in order not to load the content properties of all 25 entities.


Partial Objects

If you want to partially load entity properties that are not associations, you have to tell this Doctrine explicitly:

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

This gives you a partially loaded entity object.

But beware that partial objects are not proxies! Lazy Loading doesn't apply to them. Therefore, using partial objects is generally dangerous and should be avoided. Read more: Partial Objects — Doctrine 2 ORM 2 documentation

Kontrollfreak
  • 1,800
  • 12
  • 24
  • 1
    Thanks, this provides much more detail about how Doctrine uses Proxies and Partial Objects than the accepted answer does! And the reference to the docs is helpful too. – Sean the Bean Sep 01 '15 at 21:03
  • 1
    Also for reference, here's the section of the docs about Proxy objects: http://doctrine-orm.readthedocs.org/en/latest/reference/advanced-configuration.html#proxy-objects – Sean the Bean Sep 01 '15 at 21:10
  • So when doing an eager load, is it basically just adding result sets? –  May 20 '20 at 21:38