nattapong99 / book

0 stars 0 forks source link

Part 6: The Need for Speed #10

Open nattapong99 opened 6 years ago

nattapong99 commented 6 years ago

Symfony Service Container: The Need for Speed

ด้วยการแนะนำไฟล์ XML และ YAML config คุณอาจมีความสงสัยเกี่ยวกับประสิทธิภาพของตัว container แม้ว่า service มีการโหลดแบบ lazy loading, การอ่านกลุ่มไฟล์ XML หรือ YAML ในแต่ละ request และการสร้าง object โดยการใช้ introspection อาจไม่มีค่อยมีประสิทธิภาพในภาษา PHP และเนื่องจาก container เป็นเกือบทุกส่วนของแอพพลิเคชั่นใด ๆ ก็ตามที่ใช้มัน จึงทำให้ความเร็วเป็นเรื่องที่สำคัญเช่นกัน

ในแง่หนึ่ง การใช้ XML หรือ YAML ในการกำหนด service นั้นมีประสิทธิภาพและมีความยืดหยุ่นมาก

[php]
<container xmlns="http://symfony-project.org/2.0/container">
  <parameters>
    <parameter key="mailer.username">foo</parameter>
    <parameter key="mailer.password">bar</parameter>
    <parameter key="mailer.class">Zend_Mail</parameter>
  </parameters>
  <services>
    <service id="mail.transport" class="Zend_Mail_Transport_Smtp" shared="false">
      <argument>smtp.gmail.com</argument>
      <argument type="collection">
        <argument key="auth">login</argument>
        <argument key="username">%mailer.username%</argument>
        <argument key="password">%mailer.password%</argument>
        <argument key="ssl">ssl</argument>
        <argument key="port">true</argument>
      </argument>
    </service>
    <service id="mailer" class="%mailer.class%">
      <call method="setDefaultTransport">
        <argument type="service" id="mail.transport" />
      </call>
    </service>
  </services>
</container>

แต่ในทางกลับกัน การระบุ service container เป็นคลาส PHP ธรรมดาให้ความเร็วกับคุณ

01

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

คุณจะทำอย่างไรเพื่อให้ได้ทั้งสองสิ่งที่ดีที่สุด คำตอบนั้นง่ายมาก โดย Dependency Injection component ของ Symfony ยังมีตัว built-in dumper อีกตัวคือ PHP dumper ด้วย dumper ตัวนี้สามารถแปลง service container ใด ๆ ก็ตามให้กลายเป็นคลาส PHP ธรรมดาได้ ซึ่งมันสามารถช่วยในการ generate code ของคุณ

จากตัวอย่าง Zend_Mail

02

คลาส sfServiceContainerDumperPhp ต้องการ container เป็นอาร์กิวเมนต์ตัวแรกสำหรับ constructor โดยเมธอด dump() ใช้อาร์เรย์ของอ็อพชันและหนึ่งในนั้นเป็นชื่อของคลาสที่สร้างขึ้น

นี่คือ generated code ที่ได้

03

ถ้าคุณได้เห็น generated code ที่เกิดขึ้นโดย dumper คุณจะสังเกตุเห็นว่าโค้ดมีความคล้ายคลึงกับที่เราเขียนเอง

การ generated code ไม่ได้ใช้คีย์ลัดเพื่อเข้าถึง parameter และ service

ด้วยการใช้ sfServiceContainerDumperPhp ทำให้คุณมีทั้งสองสิ่งที่ดีที่สุดคือ ความยืดหยุ่นที่มาจากรูปแบบไฟล์ XML หรือ YAML ที่ใช้สำหรับการ config service และความเร็วที่มาจาก optimized และ auto-generated ไฟล์ PHP

เป็นที่แน่นอนว่าโปรเจ็คต่าง ๆ มีการตั้งค่าที่แตกต่างกันไปสำหรับ environment ที่แตกต่างกัน คุณสามารถสร้างคลาส container ที่แตกต่างกันเพื่อใช้กับ environment นั้น ๆ หรือใช้กับการตั้งค่า debugging ต่อไปนี้เป็นตัวอย่าง PHP code ที่อธิบายวิธีการสร้าง container แบบไดนามิกสำหรับ first request และใช้ cached สำหรับ request อื่น ๆ ทั้งหมดเมื่อไม่ได้อยู่ใน debugging mode

04

ก่อนที่จะจบบทความ มีคุณสมบัติดี ๆ อย่างนึงของ dumpper ที่อยากแสดงให้เห็น โดย Dumper สามารถทำสิ่งต่าง ๆ ได้มากมายและเพื่อให้เห็นภาพของการลดการยึดติดของการใช้งาน component เพื่อช่วยให้คุณมองเห็นภาพ service และ dependency ของมัน จึงได้นำ Graphviz dumper มาใช้งาน

ลองดูวิธีการใช้งานจากตัวอย่าง

05

Graphviz dumper สร้างการแสดงผลแบบ dot ใน container ของคุณ

digraph sc {
  ratio="compress"
  node [fontsize="11" fontname="Myriad" shape="record"];
  edge [fontsize="9" fontname="Myriad" color="grey" arrowhead="open" arrowsize="0.5"];

  node_service_container [label="service_container\nsfServiceContainerBuilder\n", shape=record, fillcolor="#9999ff", style="filled"];
  node_mail_transport [label="mail.transport\nZend_Mail_Transport_Smtp\n", shape=record, fillcolor="#eeeeee", style="dotted"];
  node_mailer [label="mailer\nZend_Mail\n", shape=record, fillcolor="#eeeeee", style="filled"];
  node_mailer -> node_mail_transport [label="setDefaultTransport()" style="dashed"];
}

การแสดงผลสามารถแปลงเป็นรูปภาพได้โดยใช้ dot_program

06

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

The Graphviz dumper เมธอด dump() มีความสามารถที่จะแสดงกราฟในแบบต่าง ๆ ได้

  • graph: ตัวเลือกเริ่มต้นสำหรับกราฟ
  • node: ตัวเลือกเริ่มต้นสำหรับ nodes
  • edge: ตัวเลือกเรื่มต้นสำหรับ edges
  • node.instance: ตัวเลือกเริ่มต้นสำหรับ service โดยสามารถระบุได้โดยตรงผ่าน object instance
  • node.definition: ตัวเลือกเริ่มต้นสำหรับ service โดยสามารถระบุผ่าน service definition instances
  • node.missing: ตัวเลือกเริ่มต้นสำหรับ missing service

นี่คือกราฟสำหรับ hypothetic CMS ที่ใช้กับ Symfony 2 new Templating Framework

07

จากบทความทั้งหมดของ Dependency Injection ที่ผ่านมา หวังว่าคุณจะได้เรียนรู้อะไรบางอย่างจากการอ่านบทความนี้

source