เริ่มต้นอย่างรวดเร็ว) ฉีด Symfony (DI Dependency Tutorial

โดย Watkin Steven Lloyd , วันเสาร์ 14 สิงหาคม 2010 14:21

คืออะไร Dependency Injection (DI)?

ฉีด Dependency เป็นเทคนิคที่ช่วยให้การประกอบวัตถุอย่างอิสระภายในโปรแกรมซอฟต์แวร์ โดยทั่วไปถ้าวัตถุต้องเข้าถึงฟังก์ชันการทำงานของผู้อื่นมันจะ instantiated ภายในที่นำไปสู่​​ระบบการประกอบแน่น โดยการใช้การฉีดขึ้นต่อเราฉีดวัตถุต้องพร้อมใช้งาน (บางครั้งยังเรียกการผกผันของการควบคุม -- IOC) ใช้ตัวอย่างต่อไปนี้

  <? PHP
 ชั้น DecisionMaker {
     makeDecision ทำงานสาธารณะ (array พารามิเตอร์ $) {
         / / ต้องการอะแดปเตอร์ฐานข้อมูล
         DP = $ DecisionParameters ใหม่ ();
         $ parameterScore = getScore $ DP -> ($ ตัวแปร);
         * / ...  ตรรกะในการตัดสินใจบางรายละเอียดเพิ่มเติม ...  * /
         กลับมา ($ parameterScore> 50);
     }
 } 

ชิ้นส่วนของรหัสนี้จะมีการบอกกับคู่ให้แน่นเพื่อ DecisionParameters วัตถุ เขียนข้างต้นในแฟชั่นคู่อย่างอิสระเราจะได้สิ่งที่ต้องการ ...

  <? PHP
 ชั้น DecisionMaker {
     ส่วนตัว $ _dp;
     ทำงานสาธารณะ __construct ($ DP) {
         $ this -> _dp = $ DP;
     }
     makeDecision ทำงานสาธารณะ (array พารามิเตอร์ $) {
         $ parameterScore = _dp -> $ this -> getScore ($ ตัวแปร);
         * / ...  ตรรกะในการตัดสินใจบางรายละเอียดเพิ่มเติม ...  * /
         กลับมา ($ parameterScore> 50);
     }
 } 

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

  ทางเลือกใหม่ = $ DecisionMaker ();
 makeDecision echo $ ตัวเลือก -> (array ('ความพยายาม'=>'กลับ''ต่ำ'=>'สูง')); 

ขณะนี้เป็น :

  DP = $ DecisionParameters ใหม่ ();
 $ = ทางเลือกใหม่ DecisionMaker ($ DP);
 makeDecision echo $ ตัวเลือก -> (array ('ความพยายาม'=>'กลับ''ต่ำ'=>'สูง')); 

สถานการณ์เช่นนี้จะกลายเป็นความเจ็บปวดมากขึ้นเป็นตัวเลขของการอ้างอิงสำหรับชั้นเรียนเพิ่มขึ้นและสิ่งที่ถ้ามีการอ้างอิงตัวเอง dependencies? ได้อย่างรวดเร็วนี้ค่อนข้างจะเป็นฝันร้ายของการบริหารวัตถุ! ใส่ภาชนะบรรจุที่พึ่งพาการฉีด (หรือกรอบ) ...

Dependency ภาชนะบรรจุยาฉีด / กรอบแนวทาง

Dependency ภาชนะบรรจุยาฉีด (หรือกรอบ) มือจับขั้นตอนของการวัตถุ; instantiating และฉีดอ้างอิงใด ๆ ก่อนที่จะกลับไปยังผู้โทรอินสแตนซ์

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

Symfony คอนเทนเนอร์ Dependency Injection

Symfony น่าจะรู้จักกันดีที่สุดสำหรับเต็มของพวกเขา stack MVC กรอบการทำงาน แต่พวกเขาได้ออกยังเป็นอิสระจำนวนของชิ้นส่วนที่สามารถใช้ ตัวอย่างเช่นการพึ่งพาการฉีดภาชนะที่เรากำลังจะพูดคุยเกี่ยวกับที่นี่, YAML parser, เครื่องยนต์ templating ให้ดู ชิ้นส่วน Symfony สำหรับข้อมูลเพิ่มเติม

DI ภาชนะ Symfony จะขึ้นอยู่กับว่าจาก Spring Framework ใน Java .

Bootstrapping

เพื่อที่จะ bootstrap กรอบ Symfony พึ่งพาการฉีดเราจะใช้รหัสเป็นรวมอยู่ด้านล่าง ฉันได้เลือกที่จะใช้ YAML เพียงเพราะง่ายต่อการอ่านและการตั้งค่าของ สำหรับความเร็วสูงสุดที่คุณอาจต้องการที่จะเขียนออกภาชนะบรรจุของคุณจะธรรมดา PHP (ภาชนะ Symfony สามารถทำเพื่อคุณเมื่อการติดตั้ง) หรืออีกทางเลือกหนึ่งแคชใช้ภาชนะทั้งหมด Zend_Cache หรือที่คล้ายกัน

หากต้องการติดตั้ง Symfony DI ทำตามคำแนะนำในที่นี้ http://components.symfony-project.org/dependency-injection/installation , และเพิ่มในเส้นทางของคุณ

  / / โหลดภาชนะ Symfony DI
 ต้อง'sfServiceContainerBuilder.php';
 ภาชนะ = $ sfServiceContainerBuilder ใหม่ ();
 $ loader = sfServiceContainerLoaderFileYaml ใหม่ ($ ภาชนะ);
 โหลด $ loader -> (APPLICATION_PATH'/ config / di / services.yml'.) 

ประการแรกที่เรายกตัวอย่างภาชนะใหม่แล้วเราโหลดการตั้งค่าของเราจากไฟล์ YAML หมายเหตุ : ภาชนะ DI สามารถโหลด config จากหลายรูปแบบเช่น XML , YAML, PHP, และ INI *. ฉันมักจะรวมไฟล์ YAML เดียวและไฟล์อื่น ๆ นำเข้าจากภายในมี

กำหนดค่าไฟล์จำนวนมากสามารถนำเข้าโดยใช้รูปแบบที่แตกต่างกันความหมายที่เขียนทับใหม่ที่ยังไม่ได้กำหนดไว้ แฟ้มการกำหนดค่าอาจรวมถึงการอ้างอิงถึงวัตถุและพารามิเตอร์

* INI เพียงสามารถกำหนดค่าพารามิเตอร์และไม่สามารถนำเข้าไฟล์อื่น ๆ

ตัวอย่างการกำหนดค่า

  นำเข้า :
 -- {ทรัพยากร : daos.yml}

 พารามิเตอร์ :
 ชื่อผู้ใช้ : เท็จ

 บริการ :
 # รูปแบบของลูกค้า
 model.customer :
 ชั้น : Pro_Customer
 โทร :
 -- [setLogger, [utils.logger] @]
 -- [setDao, [@ data.userdata.mysql]]
       -- [setUserName,% ชื่อผู้ใช้ [%]]

 # รูปแบบสินค้า
 model.product :
 ชั้น : Pro_Product
     อาร์กิวเมนต์ : [%% ชื่อผู้ใช้, {type :%% accesslevel, lastlogin :% lastlogin%}]
 โทร :
 -- [setDao, [@ data.product.mysql]]

 # คนตัดไม้
 utils.logger :
 ชั้น : Pro_Logger
     สร้าง : getInstance
 โทร :
 -- [setHandle, [utils.filewriter] @] 

ฉันคิดว่าโค้ดด้านบนเป็นธรรมคำอธิบายตนเอง แต่เพื่อความชัดเจนฉันจะอธิบายแต่ละส่วนในขณะนี้

ก่อนปิดเรากำหนดการนำเข้าบางส่วน (เช่นไฟล์อื่น ๆ เพื่อแยกวิเคราะห์) ผมชอบไปยังกลุ่มการกำหนดค่าของฉันสำหรับ DAOs ตัวอย่างในไฟล์เดียวสาธารณูปโภคในอื่นและชื่อไฟล์ได้อย่างเหมาะสม ขณะที่ช้าลงจะเพิ่มความเร็วในการบำรุงรักษาของการกำหนดค่าไฟล์ อาจเป็นไปได้ในการแยกไฟล์รูปแบบอื่น ๆ โดยใช้แฟล็กนำเข้าที่แตกต่างกัน แฟ้มจะถูกแยกวิเคราะห์ในลำดับที่มีข้อกำหนดใหม่เขียนทับหรือแก้ไขเพิ่มเติมที่กำหนดไว้ก่อนหน้านี้บริการ / พารามิเตอร์

ต่อไปเรากำหนดพารามิเตอร์, พารามิเตอร์ที่อาจจะมีชนิดตัวแปร PHP ณ จุดนี้ผมไม่ทราบว่าพารามิเตอร์ชื่อผู้ใช้ของฉันควรจะ (ฉันจำเป็นต้องตรวจสอบให้ว่า!) ดังนั้นฉันได้กำหนดค่าเริ่มต้นและฉันจะเขียนทับค่าที่ภายหลัง ชั้นเรียนหมายเหตุยังไม่ได้ instantiated จนกว่าคุณจะถามพวกเขาเพื่อกำหนดพารามิเตอร์เพียงเล็กน้อยต่อมาเป็นเรื่องปกติอย่างสมบูรณ์แบบ ต่อไปนี้ผมกำหนดให้บริการบางอย่าง

  1. ยกตัวอย่าง Pro_Customer ผ่านตัวอย่างเช่นคนตัดไม้ของฉันของฉัน setLogger () วิธีการเพิ่มใน MySQL การเข้าถึงข้อมูลวัตถุ (DAO), และส่งผ่านชื่อผู้ใช้เช่นกัน ทุกครั้งที่ผมถามสำหรับวัตถุนี้แต่ละฉันต้องการตัวอย่างใหม่
  2. สร้างอินสแตนซ์ของ Pro_Product ผ่านอาร์กิวเมนต์ของอาร์เรย์ชื่อผู้ใช้และตัวเลือกในการจัดสร้าง หลังจาก setDao โทร instantiation () และส่งผ่านสินค้าไอทีของฉัน DAO
  3. ให้ฉันสำเนาของ Pro_Logger, ยกตัวอย่างโดยใช้ getInstance () วิธีการและส่งสำเนาของวัตถุนักเขียนของฉันไฟล์ผ่าน setHandle () ครั้งที่โหลด นักเขียนไฟล์ของฉันถูกกำหนดไว้ในหนึ่งของการนำเข้าของฉัน

ภายในกำหนดค่าบริการไฟล์ที่อ้างอิงจาก prepending ชื่อกับ @'สัญลักษณ์', พารามิเตอร์อ้างอิงโดย prepending และต่อท้ายด้วย'%'สัญลักษณ์ eg@utils.logger%% ชื่อผู้ใช้

โพสต์ข้อมูลการเพิ่มโหลด

บางครั้งคุณอาจไม่ทราบว่าค่าพารามิเตอร์ของควรจะจนกว่าคุณจะมี bootstrapped เช่นเดียวกับพารามิเตอร์ชื่อผู้ใช้ของเราด้านบน เพื่อที่จะเขียนทับค่า offsetSet () วิธีใช้ขั้นแรกผ่านชื่อตัวแปรตามด้วยค่าใหม่ของมัน

  offsetSet $​​ ภาชนะ -> ('ชื่อผู้ใช้', $ ชื่อผู้ใช้); 

เริ่มจากภาชนะบรรจุวัตถุ

การตั้งค่าเมื่อมากกว่า instantiating วัตถุโดยตรงตอนนี้เราไปที่ตู้ DI ที่จะได้รับอินสแตนซ์ ด้วย Symfony DI เราเรียก getService () วิธีการผ่านในเช่นสตริงที่จะอธิบายถึงตัวแปรที่คุณต้องการดึง

  คนตัดไม้ $ = getService $ ภาชนะ -> ('utils.logger'); 

นี้จะมีประสิทธิภาพเทียบเท่ากับการ :

  $ = Pro_Logger คนตัดไม้ : : getInstance ();
 fileWriter = $ Pro_Writer_FileWriter ใหม่ ();
 $ setHandler Logger -> ($ fileWriter); 

มันเป็นไปได้ที่จะตรวจสอบว่าภาชนะบรรจุมีบริการอินสแตนซ์ของโดยการเรียก hasService () วิธีการที่จะส่งกลับค่าบูลีน

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

การทดสอบหน่วย

พึ่งพาการฉีดยังมีสิทธิประโยชน์เพิ่มเติมของวัตถุที่อนุญาตให้มีการทดสอบในการแยก ตัวอย่างเช่นการเรียน DecisionMaker ก่อนดำเนินการติดตั้งหัวฉีดขึ้นต่อผลการทดสอบของเราก็มีขึ้นอยู่กับระดับการดำเนินการตาม DecisionParameters

หากผลการเรียน DecisionParameters ที่แตกต่างกันกลับการทดสอบของเราสามารถเริ่มทำงานได้ผ่านความล้มเหลวของตัวเองไม่มีความผิดของเรา การใช้ยาฉีดพึ่งพาเราสามารถผ่านในขณะนี้ซึ่งจะส่งกลับวัตถุ DecisionParameters ทราบ / คงที่ตั้งของผลสำหรับป้อนพารามิเตอร์บางอย่างเราตอนนี้ทดสอบ DecisionMaker ในการแยกจากปัจจัยภายนอกใด ๆ เช่นถ้าการทดสอบของเราเริ่มต้นล้มเหลวนี้สามารถบันทึกโดยตรงไปยังบางสิ่งบางอย่าง การเปลี่ยนแปลงในชั้นเรียน DecisionMakeer ซึ่งเป็นสิ่งสำคัญโดยเฉพาะอย่างยิ่งหากท่านจะอาศัยการทดสอบข้อมูลจากฐานข้อมูลสำหรับการทดสอบ

การกำหนดค่าการสมัคร

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

จำแนกตามประเภท hinting บนอินเตอร์เฟซการใช้งานมากกว่าเมื่อตั้งค่าการอ้างอิงของคุณได้นอกจากนี้ยังสามารถสลับออกมาประกอบการชิ้นส่วนเข้ากันได้กับไม่กี่บรรทัดของ YAML หรือ XML ตัวอย่างเช่นคุณขณะนี้อาจเข้าถึงฐานข้อมูลของคุณผ่าน MySQL DAO (Data Access Object) แต่ในเวลาที่คุณอาจพัฒนา PDO, Zend_Db หรือ ลัทธิ การดำเนินการตาม DAO นี้ โดยการเพิ่มการใช้ใหม่ลงในแฟ้มกำหนดค่าของคุณก็วัตถุทั้งหมดที่ใช้ในการดำเนิน MySQL เก่าตอนนี้ใช้การดำเนินงานใหม่ของคุณโดยไม่จำเป็นต้องโจมตีบาดาลของใบสมัครของคุณ

Notes

  • โดยการตั้งค่าที่ใช้ร่วมกัน : เป็นจริงในการกำหนดค่าที่เราจะได้รับอยู่เสมอเช่นเดียวกับวัตถุ ซึ่งจะเป็นประโยชน์มากเมื่อจัดการกับวัตถุที่มีทรัพยากรเช่นการเชื่อมต่อฐานข้อมูล, ไฟล์จัดการและอื่น ๆ
  • มีสองวิธีการที่ขึ้นต่อกันสามารถฉีดเป็น หนึ่งคือการส่งผ่านความขึ้นกับตัวสร้างหรืออีกทางเลือกหนึ่งตัวตั้งค่าผ่านทางวิธีการ รูปแบบที่ยอมรับกันโดยทั่วไปจะต้องผ่านการขึ้นต่อกันผ่านทางตัวสร้างและ optionals ผ่าน setters การตั้งค่าส่วนตัวของฉันคือการใช้ setters สำหรับทุกอย่าง แต่นี้ลงไปยังผู้พัฒนารายบุคคล

สุดท้าย ...

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

4 ตอบไปที่"การเริ่มต้นฉบับย่อ Symfony DI (Dependency Injection) Tutorial"

  1. [...] โพสต์นี้ได้กล่าวถึงใน Twitter โดย Vincent Jousse, Steven Lloyd Watkin Steven Lloyd Watkin กล่าวว่า http://bit.ly/cUO2ov เริ่มต้นอย่างรวดเร็วสำหรับการฉีด symfony # # กรอบการพึ่งพา PHP ZF # [...]

  2. Hari KT says :

    บทความยอดเยี่ยม
    ผมมีข้อสงสัยในขณะนี้ เมื่อ bootstrapping เราจะโหลดแฟ้มการกำหนดค่า yaml ที่ไม่ให้สร้างวัตถุสำหรับทุกคนที่เราไม่จำเป็นต้อง?
    สำหรับเช่น : ฉันมีบางสิ่งบางอย่างชั้นที่จะใช้เพียงบางครั้ง ดังนั้นมันจะสร้างวัตถุหรือมันคือสมาร์ทพอที่จะโหลดผ่านทางฟังก์ชั่น autoload เมื่อฉันโทร getInstance () method ฉันไม่ได้ว่านั่นคือเหตุผลที่

    ขอขอบคุณ

  3. ไม่มีชั้นเรียนมีการโหลดเฉพาะเมื่อพวกเขาจะต้องแรก

    ใน getInstance () ตัวอย่างเช่นชั้นเป็น instantiated ชอบ
    $ ชั้น Class = : : getInstance ();
    แทนที่จะ :
    class = $ Class ใหม่ ();
    โดยทั่วไปจะใช้เมื่อมีการใช้รูปแบบเดี่ยว

  4. [...] ปล่อยให้คุณใช้ DI ในโครงการของคุณในวิธีที่ง่าย Steven Lloyd Watkin ใช้เวลาของเขาในการเขียน tutorial.It เริ่มต้นอย่างรวดเร็วของมูลค่าการพูดถึงว่า Symfony DI คอนเทนเนอร์เป็นห้องสมุดเดี่ยวใช้ได้เป็น Symfony [...]

ปล่อยให้ตอบกลับ













ชุดรูปแบบพาโนรามาโดย Themocracy

5 ผู้เข้าชมออนไลน์ขณะนี้
3 แขก, 2 บอ, 0 สมาชิก
ผู้เข้าชมสูงสุดวันนี้ : 17 ที่ 12:28 UTC
เดือนนี้ : 26 ที่ 2011/07/05 12:35 UTC
ปีนี้ : 130 ที่ 28-03-2011 10:40 UTC
เวลาทั้งหมด : 130 ที่ 28-03-2011 10:40 UTC