Що таке проксі в доктрині 2?


112

Щойно я закінчив прочитати всю документацію доктрини 2, я запустив власну пісочницю, я зрозумів більшість принципів, але все ще виникає питання, і я не зміг знайти жодного повного пояснення в документі.

  1. Що таке Proxyзаняття?
  2. Коли я повинен використовувати їх над сутностями?

Наскільки я розумію, проксі-класи додають шар, щоб ви могли додати деякі інші функції для ваших об'єктів, але навіщо використовувати проксі, а не реалізовувати самі методи в класі сутності?

Відповіді:


160

ОНОВЛЕННЯ

Ця відповідь містить неправильну інформацію про відмінності між проксі-об'єктами та частковими об'єктами. Дивіться відповідь @ Kontrollfreak для отримання більш детальної інформації: https://stackoverflow.com/a/17787070/252591


Об'єкти проксі використовуються, коли ваш запит не повертає всіх даних, необхідних для створення об'єкта. Уявіть наступний сценарій:

@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

Як ви бачите, цей запит не повертається firstnameта lastnameвластивості, тому ви не можете створити Userоб'єкт. Створення неповної сутності може призвести до несподіваних помилок.

Ось чому Доктрина створить 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;
    }
}

Дякую за вашу відповідь, чим це відрізняється від Часткового об’єкта? Я маю на увазі, чому я повинен використовувати проксі? Чому ледачу завантаження не можна здійснити в самому Entitiy? Чи можете ви надати мені випадок використання?
Jérémy

1
Часткові об'єкти та проксі-об'єкти - це одне і те ж - їх можна трактувати як синоніми. Що стосується решти запитань, перевірте мою оновлену відповідь.
Крозін

1
Я не розумію, чому доктрина не може створити об'єкт, якщо він має лише половину властивостей. У php я можу створити об’єкт, навіть якщо я не встановлюю всі властивості.
Сандерс

1
Це абсолютно приголомшлива відповідь і має бути в документації.
Джимбо

7
Ця відповідь містить деякі серйозні помилки проксі та часткових об'єктів. Дивіться мою відповідь, щоб зрозуміти, чому.
Kontrollfreak

81

Проксі

Проксі-сервер Doctrine - це лише обгортка, яка розширює клас сутності, щоб забезпечити для нього Lazy Loading.

За замовчуванням, коли ви запитуєте диспетчера сутності для сутності, асоційованої з іншим об'єктом, асоційоване об'єкт не завантажуватиметься з бази даних, а загортається у проксі-об'єкт. Коли ваша програма потім запитує властивість або викликає метод цього проксі-об'єкта, Doctrine завантажить об'єкт із бази даних (за винятком випадків, коли ви вимагаєте ідентифікатор, який завжди відомий проксі).

Це трапляється повністю прозорим для вашої програми через те, що проксі розширює ваш клас сутності.

Доктрина за замовчуванням гідратує асоціації як ледачі завантаження проксі-серверів, якщо ви не введете JOINїх у своєму запиті або встановите режим отримання EAGER.


Тепер я повинен додати це, оскільки мені не вистачає репутації, щоб коментувати всюди:

На жаль, відповідь Крозіна містить дезінформацію.

Якщо ви виконуєте такий запит DQL

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

ви отримаєте не об'єкт (проксі) сутності, а асоціативний масив. Тож не можна ледаче завантажувати будь-які додаткові властивості.

Зважаючи на це, можна дійти висновку, що і приклад використання не працюватиме. DQL повинен бути змінений на щось подібне, щоб отримати доступ $articleдо об'єкта:

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

Це дає вам частково завантажений об'єкт сутності.

Але будьте уважні, що часткові об’єкти - це не проксі! Ледаче завантаження не стосується їх. Тому використання часткових предметів, як правило, небезпечно і слід уникати. Детальніше: Часткові об'єкти - Документа 2 ORM 2 документація


1
Дякую, це надає набагато більше деталей про те, як Доктрина використовує проксі та часткові об'єкти, ніж прийнята відповідь! І посилання на документи також корисна.
Sean The Bean

1
Також для довідки, ось розділ документів про об’єкти проксі: doctrine-orm.readthedocs.org/en/latest/reference/…
Sean the Bean

Тож, роблячи нетерпляче навантаження, це в основному лише додавання наборів результатів?
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.