พร็อกซีในหลักคำสอน 2 คืออะไร?


112

ฉันเพิ่งอ่านเอกสารหลักคำสอน 2 ทั้งหมดเสร็จฉันเริ่ม Sandbox ของตัวเองฉันเข้าใจหลักการส่วนใหญ่แล้ว แต่ยังมีคำถามและฉันไม่พบคำอธิบายที่สมบูรณ์ในเอกสาร

  1. อะไรคือProxyการเรียน?
  2. เมื่อใดที่ฉันควรใช้กับเอนทิตี

เท่าที่ฉันเข้าใจคลาสพร็อกซีจะเพิ่มเลเยอร์เพื่อให้คุณสามารถเพิ่มคุณสมบัติอื่น ๆ ให้กับเอนทิตีของคุณได้ แต่ทำไมต้องใช้พร็อกซีแทนที่จะใช้เมธอดในคลาสเอนทิตี

คำตอบ:


160

UPDATE

คำตอบนี้มีข้อมูลที่ไม่ถูกต้องเกี่ยวกับความแตกต่างระหว่างวัตถุพร็อกซีและวัตถุบางส่วน ดูคำตอบของ @ 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วัตถุได้ การสร้างเอนทิตีที่ไม่สมบูรณ์อาจทำให้เกิดข้อผิดพลาดที่ไม่คาดคิด

นั่นเป็นเหตุผลที่ Doctrine สร้างUserProxyวัตถุที่รองรับการโหลดแบบขี้เกียจ เมื่อคุณพยายามเข้าถึงfirstnameคุณสมบัติ (ซึ่งไม่ได้โหลด) ระบบจะโหลดค่านั้นจากฐานข้อมูลก่อน


ฉันหมายถึงเหตุใดฉันจึงควรใช้พร็อกซี

คุณควรเขียนโค้ดของคุณราวกับว่าคุณไม่ได้ใช้วัตถุพร็อกซีเลย สามารถถือเป็นสิ่งของภายในที่ Doctrine ใช้

ทำไมการโหลดแบบขี้เกียจจึงไม่สามารถใช้งานได้ในตัวสิทธิเอง?

ในทางเทคนิคอาจเป็นได้ แต่ลองดูที่คลาสของวัตถุพร็อกซีแบบสุ่ม มันเต็มไปด้วยรหัสสกปรกเอ่อ เป็นเรื่องดีที่มีรหัสที่สะอาดในเอนทิตีของคุณ

คุณสามารถระบุกรณีการใช้งานได้หรือไม่?

คุณกำลังแสดงรายการ 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 อย่างไร? ฉันหมายถึงเหตุใดฉันจึงควรใช้พร็อกซี ทำไมการโหลดแบบขี้เกียจจึงไม่สามารถใช้งานได้ในตัวสิทธิเอง? คุณสามารถระบุกรณีการใช้งานได้หรือไม่?
Jérémy

1
วัตถุบางส่วนและวัตถุพร็อกซีเป็นสิ่งเดียวกัน - สามารถถือว่าเป็นคำพ้องความหมายได้ สำหรับคำถามที่เหลือโปรดตรวจสอบคำตอบที่อัปเดตของฉัน
Crozin

1
ฉันไม่เข้าใจว่าทำไมหลักคำสอนไม่สามารถสร้างวัตถุได้ถ้ามันมีคุณสมบัติเพียงครึ่งเดียว ใน php ฉันสามารถสร้างวัตถุได้แม้ว่าฉันจะไม่ได้ตั้งค่าคุณสมบัติทั้งหมดก็ตาม
แซนเดอร์

1
นี่เป็นคำตอบที่ยอดเยี่ยมมากและควรอยู่ในเอกสารประกอบ
Jimbo

7
คำตอบนี้มีความเข้าใจผิดอย่างร้ายแรงเกี่ยวกับพร็อกซีและวัตถุบางส่วน ดูคำตอบของฉันเพื่อทำความเข้าใจว่าทำไม
Kontrollfreak

81

ผู้รับมอบฉันทะ

Doctrine proxy เป็นเพียงกระดาษห่อหุ้มที่ขยายคลาสเอนทิตีเพื่อให้ Lazy Loading สำหรับมัน

โดยค่าเริ่มต้นเมื่อคุณขอให้ผู้จัดการเอนทิตีสำหรับเอนทิตีที่เชื่อมโยงกับเอนทิตีอื่นเอนทิตีที่เกี่ยวข้องจะไม่ถูกโหลดจากฐานข้อมูล แต่รวมอยู่ในวัตถุพร็อกซี เมื่อแอปพลิเคชันของคุณร้องขอคุณสมบัติหรือเรียกใช้เมธอดของเอนทิตีพร็อกซีนี้ Doctrine จะโหลดเอนทิตีจากฐานข้อมูล (ยกเว้นเมื่อคุณร้องขอ ID ซึ่งพร็อกซีจะรู้เสมอ)

สิ่งนี้เกิดขึ้นอย่างโปร่งใสกับแอปพลิเคชันของคุณเนื่องจากพร็อกซีขยายคลาสเอนทิตีของคุณ

หลักคำสอนจะโดยสมาคมมือไม่ถึงเริ่มต้นเป็นผู้รับมอบฉันทะโหลดขี้เกียจถ้าคุณทำไม่ได้พวกเขาในการค้นหาของคุณหรือตั้งค่าโหมดการดึงข้อมูลJOINEAGER


ตอนนี้ฉันต้องเพิ่มสิ่งนี้เพราะฉันไม่มีชื่อเสียงมากพอที่จะแสดงความคิดเห็นได้ทุกที่:

น่าเสียดายที่คำตอบของ Crozin มีข้อมูลที่ผิด

หากคุณเรียกใช้แบบสอบถาม DQL เช่น

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

คุณจะไม่ได้รับวัตถุเอนทิตี (proxied) แต่เป็นอาร์เรย์ที่เชื่อมโยง ดังนั้นจึงไม่สามารถขี้เกียจโหลดคุณสมบัติเพิ่มเติมใด ๆ

ด้วยเหตุนี้จึงมีข้อสรุปว่าตัวอย่างกรณีการใช้งานจะไม่ทำงานเช่นกัน 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

สิ่งนี้ทำให้คุณมีอ็อบเจ็กต์เอนทิตีที่โหลดบางส่วน

แต่ระวังว่าวัตถุบางส่วนไม่ใช่พร็อกซี! Lazy Loading ใช้ไม่ได้กับพวกเขา ดังนั้นโดยทั่วไปการใช้วัตถุบางส่วนจึงเป็นอันตรายและควรหลีกเลี่ยง อ่านเพิ่มเติม: Partial Objects - เอกสารหลักคำสอน 2 ORM 2


1
ขอบคุณข้อมูลนี้ให้รายละเอียดเพิ่มเติมเกี่ยวกับวิธีที่หลักคำสอนใช้ Proxies และ Partial Objects มากกว่าคำตอบที่ยอมรับ! และการอ้างอิงถึงเอกสารก็มีประโยชน์เช่นกัน
Sean the Bean

1
สำหรับการอ้างอิงนี่คือส่วนของเอกสารเกี่ยวกับวัตถุ Proxy: doctrine-orm.readthedocs.org/en/latest/reference/…
Sean the Bean

ดังนั้นเมื่อทำการโหลดอย่างกระตือรือร้นโดยพื้นฐานแล้วมันเป็นเพียงแค่การเพิ่มชุดผลลัพธ์หรือไม่?
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.