Program Club

간단한 PHP 함수에서 "종속성 주입"을 어떻게 사용할 수 있습니까?

proclub 2020. 11. 11. 20:52
반응형

간단한 PHP 함수에서 "종속성 주입"을 어떻게 사용할 수 있습니까?


나는 사람들이 의존성 주입과 그것의 이점에 대해 항상 이야기하는 것을 듣지만 나는 그것을 정말로 이해하지 못한다.

"나는 항상 데이터베이스 연결을 인수로 전달"문제에 대한 해결책인지 궁금합니다.

wikipedia의 항목을 읽으려고했지만 예제는 Java로 작성되었으므로 명확하게하려는 차이점을 확실히 이해하지 못합니다. ( http://en.wikipedia.org/wiki/Dependency_injection ).

이 dependency-injection-in-php 기사 ( http://www.potstuck.com/2009/01/08/php-dependency-injection/ )를 읽었 으며 목표는 개체에 종속성을 전달하지 않는 것 같습니다. 직접적으로, 그러나 개체의 종속성 생성과 함께 개체 생성을 차단합니다. 그래도 PHP 함수 컨텍스트를 사용하여 적용하는 방법을 모르겠습니다.

또한 다음과 같은 종속성 주입이 있으며 기능적 컨텍스트에서 종속성 주입을 시도해야합니까?

버전 1 : (매일 생성하지만 마음에 들지 않는 코드)

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

버전 2 : (데이터베이스 연결을 전달할 필요는 없지만 종속성 주입은 전달하지 않습니까?)

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();

버전 3 : ( "객체"/ 데이터의 생성은 별개이며 데이터베이스 코드는 여전히 존재합니다. 따라서 이것이 종속성 주입으로 간주 될 수 있습니까?)

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();

누구든지 방법과 이점을 명확하게 만드는 좋은 리소스 또는 통찰력을 가지고 있습니까?


의존성 주입은 "생성자에 더 많은 매개 변수가 있습니다"에 대한 큰 단어입니다.

글로벌을 좋아하지 않았을 때 끔찍한 싱글 톤 웨이브 전에했던 일입니다.

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

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

이제 트릭은 다음과 같이 단일 클래스를 사용하여 종속성을 관리하는 것입니다.

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);

당신은 단지 다른 클래스와 더 복잡하다고 생각해야합니다. 그러나 사용자 클래스는 다른 많은 클래스와 마찬가지로 메시지를 기록하기 위해 무언가가 필요할 수 있습니다. 종속성 컨테이너에 getMessageHandler 함수를 추가하고 일부 $this->_messages = $di->getMessageHandler()는 사용자 클래스에 추가하십시오. 나머지 코드에서는 변경할 사항이 없습니다.

심포니 문서 에 대한 많은 정보를 얻을 수 있습니다.


Your first example IS dependancy injection, you are injecting the dependency on the database object into the function.

Sarah has said this isn't, but imo it is, I believe she is thinking of dependency injection containers which are the next level up:

http://components.symfony-project.org/dependency-injection/trunk/book/02-Dependency-Injection-Containers


None of your examples look like dependency injection, version one is the closest though. Dependency injection is a technique used in object oriented programming, where the constructor of an object has arguments for the service objects it needs, and those service objects are passed in by the creator of the instance (which could be a factory, a test, or a dependency injection framework).

To get around your 'always passing the connection object' problem you may want to consider the template pattern. The template pattern is basically an abstract base class with the common part of a repeated code block, and abstract methods to allow for the variation between the instances of those repeated code blocks. Basically the base is a template of a block of code, and the abstract methods are the blanks to be filled in. I personally use the template method pattern to do my database resource control in Java.


I have done much searching on this topic myself (PHP Dependency Injection) and haven't found much to my liking. A lot has been written on the subject for other languages (Google Guice - http://code.google.com/p/google-guice/ ; Java Spring), but I couldn't find much available for PHP. Regardless of the language, however, the challenges are similar.

The three versions you list in your question are the typical approach. Version 3 is the closest to the direction in which I have seen the industry going. By shifting the responsibility of creating your dependent objects outside of your class, you are free to manipulate them as you please in your test code. However, the problem that I encountered with that approach is that you end up with long chains of dependent objects in your constructor that can potentially not even be used by the receiving object, but get passed through to an secondary dependent object. It gets messy and you lose knowledge of what is coming from where.

The Dependency Container example by @Arkh and @mmmshuddup is a great start, but I nonetheless found limitations with that approach as well. The final solution upon which I arrived was a custom built solution modeled somewhat after the Cake Pattern popular in Scala. It allows you to pass a single dependency into each of your constructors AND it lets you define the default construction of the dependent objects per class. This frees you from long dependency chains as well as losing control of the default implementations of your dependencies.

I called the system Diesel and I've been really happy with it. I published the code on github for anyone interested. You can get to it from the blog I wrote on the subject, which describes the basic usage as well as goes into more detail on your question. http://developers.blog.box.com/2012/02/15/introducting-diesel-php-dependency-injection/


Dependency Injection is the idea of removing the dependency between 2 components in order to focus on why they are dependent.

Imagine you have a component A that needs to use the services of another component B.

If you hardcode the existence of B inside A, then you will be stuck when you will want A to use the sames services, but implemented by another component.

So usually, you define a service interface that B and C will implement, and you make sure that when you use A, you feed it with objects compatible with the needed interface.

In your case, you might consider that your interface is a service on which you can make a query.

Your first case is the one that is the closer to the idea of Dependency Injection.

참고URL : https://stackoverflow.com/questions/2255771/how-can-i-use-dependency-injection-in-simple-php-functions-and-should-i-bothe

반응형