Quick Start Symfony DI (Injection Dependency) Hướng dẫn

Bởi Watkin Lloyd Steven , Thứ Bảy 14 Tháng 8 2010 14:21

là gì Dependency Injection (DI)?

Dependency injection là một kỹ thuật cho phép các đối tượng liên kết lỏng lẻo trong một ứng dụng phần mềm. Thông thường nếu một đối tượng cần truy cập vào các chức năng của người khác nó sẽ được khởi tạo trong nội bộ dẫn đến các hệ thống chặt chẽ cùng. Bằng cách thực hiện tiêm phụ thuộc chúng tôi đưa các đối tượng cần thiết sẵn sàng sử dụng (đôi khi còn gọi là đảo ngược kiểm soát - IOC). Lấy ví dụ sau đây:

  <? Php
 lớp DecisionMaker {
     chức năng công cộng makeDecision (mảng $ thông số) {
         / / Cần các bộ chuyển đổi cơ sở dữ liệu
         $ Dp = new DecisionParameters ();
         $ ParameterScore = $ dp-> getScore (tham số);
         / * ...  Một số logic quyết định nhiều hơn nữa ...  * /
         trở lại ($ parameterScore> 50);
     }
 } 

Đoạn mã này được cho là chặt chẽ với các DecisionParameters đối tượng. Viết lại trên một cách lỏng lẻo cùng chúng tôi muốn có một cái gì đó giống như ....

  <? Php
 lớp DecisionMaker {
     tin $ _dp;
     công chức năng __construct (dp) {
         $ This-> _dp = $ dp;
     }
     chức năng công cộng makeDecision (mảng $ thông số) {
         $ ParameterScore = $ this-> _dp-> getScore (tham số);
         / * ...  Một số logic quyết định nhiều hơn nữa ...  * /
         trở lại ($ parameterScore> 50);
     }
 } 

Trong khi đạt được những lợi ích của các mã liên kết lỏng lẻo, chúng tôi có thêm sự phức tạp như vậy mà mỗi lần một đối tượng được khởi tạo chúng tôi cũng phải khởi tạo phụ thuộc của nó và vượt qua chúng trong quá. Ví dụ, điều này:

  $ Sự lựa chọn = mới DecisionMaker ();
 makeDecision echo $ sự lựa chọn-> (array ('nỗ lực' = 'trở về'> 'thấp', => 'cao')); 

bây giờ trở thành:

 $ Dp = DecisionParameters mới (); $ sự lựa chọn = mới DecisionMaker (dp); echo makeDecision $ sự lựa chọn-> (array ('nỗ lực' = 'trở về'> 'thấp', => 'cao')); 

Tình trạng này trở nên đau đớn hơn khi số lượng phụ thuộc cho một lớp học được tăng lên, và những gì nếu các phụ thuộc mình có phụ thuộc? Điều này hoàn toàn có thể nhanh chóng trở thành một cơn ác mộng đối tượng chính! Nhập chứa tiêm phụ thuộc (hoặc khung) ...

Dependency Injection Containers / Khung

Dependency injection container (hoặc khung) xử lý quá trình tạo đối tượng; instantiating và tiêm chích bất kỳ phụ thuộc trước khi trở về một cá thể để người gọi.

Trong code của bạn hơn là tạo các đối tượng mới trực tiếp chúng tôi yêu cầu một bản sao của đối tượng từ các container DI. Các đối tượng chúng ta đang trở về đã có tất cả của nó phụ thuộc đối tượng tiêm và đã sẵn sàng để đi.

Symfony Dependency Injection Container

Symfony có lẽ là nổi tiếng với chồng của họ đầy đủ MVC framework Tuy nhiên họ cũng đã phát hành một số thành phần có thể được sử dụng độc lập. Ví dụ, các container tiêm phụ thuộc chúng ta sẽ nói về đây, một YAML phân tích cú pháp, một công cụ khuôn mẫu, xem các thành phần Symfony cho nhiều hơn nữa.

DI container Symfony được dựa trên đó từ khung Spring trong Java .

Bootstrapping

Để khởi động trong khuôn khổ Symfony tiêm phụ thuộc chúng tôi sử dụng mã như dưới đây. Tôi đã chọn để sử dụng YAML chỉ vì đọc dễ dàng của nó và thiết lập. Đối với tốc độ tối đa mà bạn có thể muốn viết ra container của bạn để đồng bằng PHP (Symfony container có thể làm điều này cho bạn khi thiết lập), hoặc cách khác chứa toàn bộ bộ nhớ cache bằng cách sử dụng Zend_Cache , hoặc tương tự.

Để cài đặt Symfony DI theo hướng dẫn bao gồm ở đây http://components.symfony-project.org/dependency-injection/installation , và thêm nó vào con đường của bạn.

  / / Nạp Symfony DI container
 yêu cầu 'sfServiceContainerBuilder.php';
 $ Container = mới sfServiceContainerBuilder ();
 $ Loader = mới sfServiceContainerLoaderFileYaml (container);
 $ Nạp-> tải (APPLICATION_PATH '/ config / di / services.yml'.); 

Trước hết chúng ta khởi tạo một container mới, và sau đó chúng tôi tải cấu hình của chúng tôi từ một file YAML. Lưu ý: các container DI có thể tải cấu hình từ một số định dạng như XML , YAML, PHP, và *. INI Tôi có xu hướng bao gồm một file YAML đơn và nhập khẩu các tập tin khác từ bên trong đó.

Một số file cấu hình có thể được nhập bằng cách sử dụng các định dạng khác nhau, các định nghĩa mới ghi đè lên những người đã được xác định. Cấu hình các tập tin có thể bao gồm tài liệu tham khảo cho các đối tượng và các thông số.

* INI là chỉ có thể xác định các thông số và không thể nhập các tập tin khác

Ví dụ cấu hình

 nhập khẩu: - {nguồn: daos.yml} thông số: tên người dùng: false dịch vụ: # mô hình khách hàng model.customer: class: Pro_Customer cuộc gọi: - [setLogger, [@ utils.logger]] - [setDao, [@ data.userdata. ]] mysql - [setUserName, [% username%]] # Sản phẩm mô hình model.product: class: Pro_Product đối số: [% username%, {kiểu:% accesslevel%, lastlogin:%% lastlogin}] cuộc gọi: - [setDao, [@ data.product.mysql]] # Logger utils.logger: class: Pro_Logger xây dựng: các cuộc gọi getInstance: - [setHandle, [@ utils.filewriter]] 

Tôi nghĩ rằng đoạn mã trên là khá tự giải thích cho rõ ràng, nhưng tôi sẽ giải thích từng phần ngay bây giờ.

Trước hết chúng ta xác định một số hàng nhập khẩu (tức là các tập tin khác để phân tích), tôi muốn nhóm các cấu hình của tôi cho DAO ví dụ trong một tập tin, tiện ích trong một và đặt tên cho tập tin thích hợp. Trong khi một chút chậm hơn nó tăng tốc độ duy trì của các tập tin cấu hình. cũng của nó có thể phân tích các tập tin định dạng khác bằng cách sử dụng lá cờ nhập khẩu khác nhau. Tập tin được phân tích để có các định nghĩa mới ghi đè lên hoặc sửa đổi dịch vụ đã xác định trước / tham số.

Tiếp theo chúng ta định nghĩa một tham số, một tham số thường có thể được bất kỳ biến PHP loại. Tại thời điểm này tôi không biết những gì tham số tên người dùng của tôi phải được (tôi cần phải chứng thực cho điều đó!), Vì vậy tôi đã xác định một giá trị mặc định và tôi sẽ ghi đè lên giá trị sau này. Lưu ý, các lớp học không được khởi tạo cho đến khi bạn yêu cầu họ để xác định các thông số ít một sau đó là hoàn toàn tốt đẹp. Sau này, tôi xác định một số dịch vụ:

  1. Khởi Pro_Customer, vượt qua một thể hiện của logger của tôi vào setLogger () phương pháp, thêm vào của tôi MySQL đối tượng truy cập dữ liệu (DAO), và thông qua tên người dùng là tốt. Mỗi lần tôi yêu cầu cho đối tượng này, tôi muốn có một thể hiện mới
  2. Tạo một thể hiện của Pro_Product, vượt qua các đối số của tên người dùng và một loạt các tùy chọn để khởi tạo. Sau khi setDao gọi instantiation () và vượt qua nó sản phẩm của tôi DAO
  3. Hãy cho tôi một bản sao của Pro_Logger, khởi tạo nó bằng cách sử dụng getInstance () phương pháp và thông qua một bản sao của đối tượng nhà văn tập tin của tôi qua setHandle () một lần nạp của nó. nhà văn tập tin của tôi được xác định tại một trong nhập khẩu của tôi.

Trong thời hạn các file cấu hình dịch vụ được tham chiếu bởi năng thêm vào trước tên với ký hiệu '@' một, tham số được tham chiếu bởi năng thêm vào trước và phụ thêm với '%' biểu tượng, eg@utils.logger% username%.

Thêm dữ liệu đăng tải

Đôi khi bạn không biết giá trị của tham số nên được cho đến sau khi bạn đã bootstrapped, như với tham số tên người dùng của chúng tôi ở trên. Để ghi đè lên giá trị offsetSet () phương pháp được sử dụng, trước hết qua tên tham số tiếp theo giá trị mới của nó:

  $ Container-> offsetSet ('username', $ username); 

Bắt đối tượng từ các container

Sau khi thiết lập chứ không phải là đối tượng trực tiếp instantiating hiện nay chúng tôi đi đến container DI để có được các trường hợp. Với DI Symfony chúng tôi gọi là getService () phương pháp, đi qua trong một chuỗi mô tả các biến bạn muốn lấy, ví dụ:

  $ Logger = $ container-> getService ('utils.logger'); 

Điều này sẽ thực hiện tương đương với:

  $ Logger = Pro_Logger:: getInstance ();
 $ FileWriter = mới Pro_Writer_FileWriter ();
 $ Logger-> setHandler ($ fileWriter); 

Nó có thể xác định nếu container có một thể hiện của một dịch vụ bằng cách gọi hasService () phương pháp, trả về một giá trị boolean.

Nó không cần thiết phải truy cập vào các container vượt quá mức đầu ứng dụng của bạn kể từ khi lấy một thể hiện tất cả các phụ thuộc yêu cầu phải xuống đáy sâu nhất của ứng dụng đã cài đặt và chờ đợi để được gọi là.

Đơn vị kiểm tra

Dependency injection cũng có lợi ích gia tăng cho phép các đối tượng được kiểm tra cách ly. Lấy ví dụ lớp DecisionMaker trước khi thực hiện cài đặt tiêm phụ thuộc kết quả kiểm tra của chúng tôi cũng phụ thuộc vào việc thực hiện các lớp DecisionParameters.

Nếu lớp DecisionParameters khác nhau trả lại kết quả xét nghiệm của chúng tôi có thể bắt đầu thất bại không phải do lỗi của chúng ta. Sử dụng tiêm phụ thuộc chúng ta có thể bây giờ vượt qua trong một đối tượng DecisionParameters mà trả về một tiếng / cố định tập hợp các kết quả cho tham số đầu vào nhất định, chúng tôi đang thử nghiệm DecisionMaker trong sự cô lập từ bất kỳ yếu tố bên ngoài, tức là nếu xét nghiệm của chúng tôi bắt đầu không trực tiếp này có thể được quy cho một cái gì đó thay đổi trong lớp DecisionMakeer. Điều này đặc biệt quan trọng bạn cần phải dựa vào các dữ liệu thử nghiệm từ một cơ sở dữ liệu để thử nghiệm.

Cấu hình ứng dụng

Cách thức mà ứng dụng của bạn cư xử trên máy chủ sản xuất của bạn chắc chắn sẽ khác với thiết lập phát triển của bạn. Ví dụ, trong một môi trường phát triển mức độ khai thác gỗ sẽ được nhiều chi tiết hơn so với trên hệ thống sản xuất của bạn. Bằng cách thay đổi phụ thuộc vào các tập tin cấu hình tiêm container của bạn một chút (hoặc phân tích một tập tin cấu hình bổ sung) các thay đổi của hành vi tùy thuộc vào môi trường là thực hiện đơn giản.

Phân theo loại gián tiếp vào giao diện chứ không phải là hiện thực khi thiết phụ thuộc của bạn của nó cũng có thể trao đổi các thành phần cho các thành phần tương thích với một vài dòng YAML hay XML. Ví dụ, bạn có thể truy cập cơ sở dữ liệu hiện tại của bạn thông qua một DAO MySQL (Data Access Object), nhưng trong thời gian bạn có thể phát triển một PDO, Zend_Db, hoặc Doctrine thực hiện DAO này. Bằng cách thêm vào thực hiện mới vào file cấu hình của bạn đột nhiên tất cả các đối tượng sử dụng thực hiện MySQL cũ hiện đang sử dụng thực hiện mới của bạn mà không cần phải tấn công vào ruột của ứng dụng.

Ghi chú

  • Bằng cách thiết lập chia sẻ: thật sự trong cấu hình của chúng tôi luôn đưa ra các ví dụ tương tự của một đối tượng. Điều này là rất hữu ích khi giao dịch với các đối tượng có chứa các tài nguyên như các kết nối cơ sở dữ liệu, file xử lý, vv
  • Có hai phương pháp mà phụ thuộc có thể được tiêm. Một là thông qua phụ thuộc với nhà xây dựng, hoặc cách khác thông qua các phương thức setter. Các mô hình được chấp nhận chung là thông qua các phụ thuộc yêu cầu thông qua các nhà xây dựng và optionals qua setters. sở thích cá nhân của tôi là sử dụng setters cho mọi thứ, nhưng đây là xuống để các nhà phát triển cá nhân

Cuối cùng ....

Cùng với một cuộc thảo luận ngắn gọn về tiêm phụ thuộc và các ưu điểm và nhược điểm này cũng đã được một hướng dẫn nhanh, bắt đầu thực hiện phụ thuộc Symfony Injection Container ... hy vọng bạn đã thấy rằng đó là đáng ngạc nhiên nhanh chóng và dễ dàng. Từ đây bạn sẽ có thể bắt đầu sử dụng dependency injection thông qua ứng dụng của bạn và xem xét để sử dụng nhiều hơn nữa trong những tính năng cao cấp (mặc dù các ví dụ đơn giản bao gồm phần lớn các chức năng bạn sẽ yêu cầu). Như mọi khi tôi chỉ cho bạn các hướng dẫn để biết thêm thông tin.

4 hồi đáp tới "Quick Start Symfony DI (Dependency Injection) Hướng dẫn"

  1. [...] Bài này đã được đề cập trên Twitter bởi Vincent Jousse, Steven Lloyd Watkin. Steven Watkin Lloyd cho biết: http://bit.ly/cUO2ov nhanh bắt đầu cho # symfony tiêm phụ thuộc khuôn khổ # php # ZF [...]

  2. Hari KT cho biết:

    Great bài viết.
    Tôi có một nghi ngờ bây giờ. Khi bootstrapping chúng ta đang tải tập tin cấu hình các yaml. Vì vậy không có tạo các đối tượng cho tất cả, mà chúng ta không cần?
    Đối với ví dụ như: Tôi có một cái gì đó lớp mà chỉ được sử dụng đôi khi. Vì vậy, nó tạo ra một đối tượng hoặc là nó đủ thông minh để tải thông qua chức năng tự động load khi tôi gọi getInstance () phương pháp. Tôi đã không nhận được điều đó, tức là lý do tại sao.

    Cảm ơn

  3. Steven Watkin Lloyd cho biết:

    Không, các lớp học chỉ nạp khi cần thiết đầu tiên.

    Trong getInstance () ví dụ lớp được khởi tạo như:
    $ Class = Class:: getInstance ();
    Thay vì:
    $ Class = new Class ();
    Nói chung này được sử dụng khi thực hiện các mô hình singleton.

  4. [...] Cho phép bạn sử dụng DI trong dự án của bạn một cách dễ dàng. Steven Lloyd Watkin dành nhiều thời gian của mình trên văn bản một tutorial.It nhanh chóng bắt đầu có giá trị để đề cập đến là Symfony DI container là một thư viện độc lập có sẵn như là một [...] Symfony

Để lại một trả lời













Chủ đề của bức tranh toàn cảnh Themocracy

6 khách online
6 khách, 0 chương trình, 0 thành viên
Max khách truy cập hôm nay: 13 lúc 12:19 giờ UTC
Trong tháng này: 26 tại 2011/07/05 12:35 giờ UTC
Trong năm nay: 130 tại 28-03-2011 10:40 UTC
Tất cả thời gian: 130 vào 28-03-2011 10:40 UTC