교리 2에서 위임장은 무엇입니까?


112

방금 모든 Doctrine 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

당신이 볼 수 있듯이이 쿼리는 반환하지 않습니다 firstnamelastname특성, 따라서 당신은 만들 수 없습니다 User개체를. 불완전한 엔터티를 만들면 예기치 않은 오류가 발생할 수 있습니다.

이것이 Doctrine이 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;
    }
}

Partial Object와 다른 점에서 답변 해 주셔서 감사합니다. 프록시를 사용해야하는 이유는 무엇입니까? 지연 로딩이 Entitiy 자체에서 구현 될 수없는 이유는 무엇입니까? 사용 사례를 제공 할 수 있습니까?
Jérémy

1
부분 개체와 프록시 개체는 동일하며 동의어로 처리 할 수 ​​있습니다. 나머지 질문에 대해서는 업데이트 된 답변을 확인하십시오.
Crozin

1
나는 왜 교리가 속성의 절반 만 가지고있는 객체를 만들 수 없는지 이해하지 못한다. PHP에서는 모든 속성을 설정하지 않아도 개체를 만들 수 있습니다.
샌더스

1
이것은 완전히 멋진 대답이며 문서에 있어야합니다.
Jimbo

7
이 답변에는 프록시 및 부분 개체에 대한 심각한 오해가 포함되어 있습니다. 이유를 이해하려면 내 대답 을 참조하십시오 .
Kontrollfreak

81

프록시

Doctrine 프록시는 엔터티 클래스를 확장하여 Lazy Loading을 제공하는 래퍼입니다.

기본적으로 엔터티 관리자에게 다른 엔터티와 연결된 엔터티를 요청하면 연결된 엔터티가 데이터베이스에서로드되지 않고 프록시 개체로 래핑됩니다. 애플리케이션이 속성을 요청하거나이 프록시 된 엔터티의 메서드를 호출하면 Doctrine은 데이터베이스에서 엔터티를로드합니다 (항상 프록시에 알려진 ID를 요청하는 경우 제외).

이것은 프록시가 엔티티 클래스를 확장한다는 사실로 인해 애플리케이션에 완전히 투명하게 발생합니다.

Doctrine은 JOIN쿼리에 연결 하지 않거나 가져 오기 모드를로 설정 하지 않으면 기본적으로 연결을 지연로드 프록시로 수화 합니다 EAGER.


이제 모든 곳에 댓글을 달 수있는 평판이 충분하지 않기 때문에 이것을 추가해야합니다.

불행히도 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

25 개 항목 getContent()의 콘텐츠 속성을 모두 로드하지 않으려면에서 반환 된 속성 이 연결이어야합니다 .


부분 개체

연결이 아닌 엔터티 속성을 부분적으로로드하려면이 Doctrine을 명시 적으로 지정해야합니다.

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

이것은 부분적으로로드 된 엔티티 객체를 제공합니다.

그러나 부분 객체 프록시 가 아닙니다 ! Lazy Loading은 적용되지 않습니다. 따라서 부분 개체를 사용하는 것은 일반적으로 위험하므로 피해야합니다. 더 읽어보기 : Partial Objects — Doctrine 2 ORM 2 documentation


1
감사합니다. 이것은 Doctrine이 수락 된 답변보다 프록시 및 부분 객체를 사용하는 방법에 대해 훨씬 더 자세한 정보를 제공합니다! 그리고 문서에 대한 참조도 도움이됩니다.
Sean the Bean

1
또한 참조를 위해, 여기에 프록시에 대한 문서의 섹션 객체의 : doctrine-orm.readthedocs.org/en/latest/reference/...
숀 빈이

그래서 eager load를 할 때 기본적으로 결과 세트를 추가하는 것입니까?
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.