2010-02-12 21 views
63

Tôi nghe mọi người nói về tiêm phụ thuộc và lợi ích của nó tất cả các thời gian, nhưng tôi không thực sự hiểu nó.Làm thế nào tôi có thể sử dụng "Dependency Injection" trong các hàm php đơn giản, và tôi có nên bận tâm không?

Tôi tự hỏi nếu đó là giải pháp cho vấn đề "Tôi vượt qua các kết nối cơ sở dữ liệu dưới dạng đối số mọi lúc".

Tôi đã thử đọc mục nhập wikipedia trên đó, nhưng ví dụ được viết bằng Java vì vậy tôi không hiểu rõ sự khác biệt mà nó đang cố gắng làm rõ. (http://en.wikipedia.org/wiki/Dependency_injection).

Tôi đọc bài viết phụ thuộc-tiêm-trong-php này (http://www.potstuck.com/2009/01/08/php-dependency-injection/), và dường như mục tiêu là không chuyển phụ thuộc trực tiếp vào đối tượng, nhưng để tạo ra một đối tượng cùng với việc tạo ra nó phụ thuộc. Tôi không chắc chắn làm thế nào để áp dụng đó trong một bối cảnh chức năng sử dụng php, mặc dù.

Ngoài ra, đây là tiêm phụ thuộc sau và tôi có nên cố gắng thực hiện tiêm phụ thuộc trong ngữ cảnh chức năng không?

Version 1: (các loại mã mà tôi tạo ra, nhưng không thích, mỗi ngày)

function get_data_from_database($database_connection){ 
    $data = $database_connection->query('blah'); 
    return $data; 
} 

Version 2: (không cần phải thông qua một kết nối cơ sở dữ liệu, nhưng có lẽ không phụ thuộc ? tiêm)

function get_database_connection(){ 
    static $db_connection; 
    if($db_connection){ 
     return $db_connection; 
    } else { 
     // create db_connection 
     ... 
    } 
} 

function get_data_from_database(){ 
    $conn = get_database_connection(); 
    $data = $conn->query('blah'); 
    return $data; 
} 

$data = get_data_from_database(); 

Phiên bản 3: (việc tạo ra các "đối tượng"/dữ liệu tách biệt, và mã cơ sở dữ liệu vẫn còn, vì vậy có lẽ điều này sẽ được tính là dependency injection)

function factory_of_data_set(){ 
    static $db_connection; 
    $data_set = null; 
    $db_connection = get_database_connection(); 
    $data_set = $db_connection->query('blah'); 
    return $data_set; 
} 

$data = factory_of_data_set(); 
?

Bất cứ ai cũng có một nguồn lực tốt hoặc chỉ là cái nhìn sâu sắc mà làm cho phương pháp và lợi ích -crystal-rõ ràng?

+0

Bạn không cần chuyển kết nối db của mình - chỉ cần khai báo nó là toàn cầu trong hàm 'global $ database_connection; ' –

Trả lời

72

Dependency Injection là một từ lớn cho " Tôi có một số thông số hơn trong constructor của tôi ".

Đó là những gì bạn đã làm trước làn sóng Singleton awfull khi bạn không thích globals:

<?php 
class User { 
    private $_db; 
    function __construct($db) { 
     $this->_db = $db; 
    } 
} 

$db = new Db(); 
$user = new User($db); 

Bây giờ, Bí quyết là sử dụng một lớp duy nhất để quản lý phụ thuộc của bạn, một cái gì đó như thế:

class DependencyContainer 
{ 
    private _instances = array(); 
    private _params = array(); 

    public function __construct($params) 
    { 
     $this->_params = $params; 
    } 

    public function getDb() 
    { 
     if (empty($this->_instances['db']) 
      || !is_a($this->_instances['db'], 'PDO') 
     ) { 
      $this->_instances['db'] = new PDO(
       $this->_params['dsn'], 
       $this->_params['dbUser'], 
       $this->_params['dbPwd'] 
      ); 
     } 
     return $this->_instances['db']; 
    } 
} 

class User 
{ 
    private $_db; 
    public function __construct(DependencyContainer $di) 
    { 
     $this->_db = $di->getDb(); 
    } 
} 

$dependencies = new DependencyContainer($someParams); 
$user = new User($dependencies); 

Bạn phải nghĩ rằng bạn chỉ là một lớp học và phức tạp hơn. Tuy nhiên, lớp người dùng của bạn có thể cần một cái gì đó để đăng nhập các tin nhắn như nhiều lớp khác. Chỉ cần thêm hàm getMessageHandler vào vùng chứa phụ thuộc của bạn và một số $this->_messages = $di->getMessageHandler() vào lớp người dùng của bạn. Không có gì để thay đổi trong phần còn lại của mã của bạn.

Bạn sẽ nhận được rất nhiều infos về symfony's doc

+2

cảm ơn bạn về ví dụ PDO bắt đầu nhanh dễ hiểu, kèm theo câu trả lời của bạn cho câu hỏi thực tế :) –

+2

Tôi cảm thấy điên rồ vì là người đầu tiên nhìn thấy nó, nhưng là từ đầu tiên trong câu trả lời tuyệt vời này không phải từ đúng? –

+0

@ThiloSavage đầu tiên đề cập đến nó. Cảm ơn. – Arkh

6

Không có ví dụ nào của bạn trông giống như tiêm phụ thuộc, phiên bản một là gần nhất. Dependency injection là một kỹ thuật được sử dụng trong lập trình hướng đối tượng, trong đó constructor của đối tượng có đối số cho các đối tượng dịch vụ cần, và các đối tượng dịch vụ được truyền vào bởi tác giả của cá thể (có thể là nhà máy, thử nghiệm hoặc một khuôn khổ tiêm phụ thuộc).

Để tránh vấn đề 'luôn chuyển đối tượng kết nối' bạn có thể muốn xem xét mẫu mẫu. Mẫu khuôn mẫu về cơ bản là một lớp cơ sở trừu tượng với phần chung của một khối mã lặp lại và các phương thức trừu tượng để cho phép biến đổi giữa các cá thể của các khối mã lặp lại đó. Về cơ bản, cơ sở là một mẫu của một khối mã, và các phương thức trừu tượng là các khoảng trắng được điền vào. Cá nhân tôi sử dụng mẫu phương thức khuôn mẫu để làm điều khiển tài nguyên cơ sở dữ liệu của tôi trong Java.

+0

http://en.wikipedia.org/wiki/Template_method_pattern? – Kzqai

+0

một trong những triển khai có thể có, vâng. –

2

Tôi đã làm nhiều cách tìm kiếm trên chủ đề này bản thân mình (PHP Dependency Injection) và đã không tìm thấy nhiều theo ý thích của tôi. Rất nhiều đã được viết về chủ đề cho các ngôn ngữ khác (Google Guice - http://code.google.com/p/google-guice/; Java Spring), nhưng tôi không thể tìm thấy nhiều sẵn có cho PHP. Bất kể ngôn ngữ, tuy nhiên, những thách thức là tương tự.

Ba phiên bản bạn liệt kê trong câu hỏi là cách tiếp cận điển hình. Phiên bản 3 là gần nhất với hướng mà tôi đã thấy ngành công nghiệp đi. Bằng cách chuyển trách nhiệm tạo ra các đối tượng phụ thuộc của bạn bên ngoài lớp học của bạn, bạn có thể tự do thao tác chúng như bạn làm trong mã thử nghiệm của mình. Tuy nhiên, vấn đề mà tôi gặp phải với cách tiếp cận đó là bạn kết thúc với các chuỗi dài các đối tượng phụ thuộc trong constructor của bạn mà có khả năng thậm chí không được sử dụng bởi đối tượng nhận, nhưng được truyền vào một đối tượng phụ thuộc thứ cấp. Nó lộn xộn và bạn mất kiến ​​thức về những gì đang đến từ đâu.

Ví dụ về Dependency Container của @Arkh và @mmmshuddup là một khởi đầu tuyệt vời, nhưng dù sao tôi cũng tìm thấy những hạn chế với cách tiếp cận đó. Giải pháp cuối cùng mà tôi đã đến là một giải pháp được xây dựng tùy chỉnh được mô hình hóa một chút sau Mẫu Bánh phổ biến ở Scala. Nó cho phép bạn chuyển một phụ thuộc duy nhất vào từng nhà xây dựng của bạn VÀ nó cho phép bạn xác định việc xây dựng mặc định của các đối tượng phụ thuộc là cho mỗi lớp. Điều này giải phóng bạn khỏi các chuỗi phụ thuộc dài cũng như mất quyền kiểm soát việc triển khai mặc định các phụ thuộc của bạn.

Tôi gọi hệ thống là Diesel và tôi thực sự hài lòng với nó. Tôi đã xuất bản mã trên github cho bất kỳ ai quan tâm. Bạn có thể truy cập từ blog mà tôi đã viết về chủ đề, mô tả cách sử dụng cơ bản cũng như đi sâu vào chi tiết hơn về câu hỏi của bạn. http://developers.blog.box.com/2012/02/15/introducting-diesel-php-dependency-injection/

2

Dependency Injection là ý tưởng loại bỏ sự phụ thuộc giữa 2 thành phần để tập trung vào lý do chúng phụ thuộc.

Hãy tưởng tượng bạn có một thành phần A mà cần phải sử dụng các dịch vụ của một thành phần B.

Nếu bạn hardcode sự tồn tại của B bên A, sau đó bạn sẽ bị mắc kẹt khi bạn sẽ muốn A sử dụng các dịch vụ sames , nhưng được thực hiện bởi một thành phần khác. Vì vậy, thông thường, bạn định nghĩa một giao diện dịch vụ mà B và C sẽ thực hiện, và bạn chắc chắn rằng khi bạn sử dụng A, bạn sẽ nạp nó với các đối tượng tương thích với giao diện cần thiết.

Trong trường hợp của bạn, bạn có thể xem giao diện của mình là dịch vụ mà bạn có thể thực hiện truy vấn.

Trường hợp đầu tiên của bạn là trường hợp gần gũi hơn với ý tưởng về tiêm phụ thuộc.

Các vấn đề liên quan