2

所以 - 我想将我的代码切换到依赖注入、依赖注入容器 (DIC) 范式。而且我一直在阅读它……在我看来,我一直在这样做……也许……

我在做什么 - 我正在为每个单独的项目创建命名空间类(容器?),我通常称之为 Api,然后我将实例化并从中获取配置的对象。实际示例:

<?php

/**
 * @namespace
 */
namespace SomeNamespace;

/**
 * api
 */
class api {
    public function __construct() {
        /*
         * Requiring all of the common files.
         */
        require_once( VENDORS_PATH . DIRECTORY_SEPARATOR . 'PHPMailer' . DIRECTORY_SEPARATOR . 'class.phpmailer.php' );
        require_once( VENDORS_PATH . DIRECTORY_SEPARATOR . 'PHPMailer' . DIRECTORY_SEPARATOR . 'class.smtp.php' );
    }

    private function getPostgresqlPreprocessor() {
        $spp = new \SomeNamespace\Utils\PostgresSearchPreProcessor();
        $settingsService = $this->getSettingsService();
        $settings = $settingsService->readSettings();
        $spp->setValidator( new \Auro\Validation\Validator() )
            ->setSettings( $settings )
            ->setConfig( require( CONFIGS_PATH . DIRECTORY_SEPARATOR . 'models_craig_config.php' ) );
        return $spp;
    }

    public function getDalApi() {
        return new \DalServices\Api();
    }

    public function getFeedsService() {
        $fc = \Auro\Mvc\Front::getInstance();
        $feedsService = new \SomeNamespace\Feeds();
        $renderer = new \Auro\View\Renderer();
        $renderer->setBasePath( VIEWS_PATH . DIRECTORY_SEPARATOR . 'feeds' );

        $feedsService
            ->setDalApi( new \DalServices\Api() )
            ->setSomeNamespaceApi( $this )
            ->setResponse( $fc->getResponse() )
            ->setPaginator( new \Auro\View\Paginator() )            
            ->setConfig( require( CONFIGS_PATH . DIRECTORY_SEPARATOR . 'models_feeds_config.php' ) )
            ->setCams( require( CONFIGS_PATH . DIRECTORY_SEPARATOR . 'webcams.php' ) )
            ->setRenderer( $renderer );
        return $feedsService;
    }

    public function getSettingsService() {
        $fc = \Auro\Mvc\Front::getInstance();
        $settingsService = new \SomeNamespace\Settings;
        $renderer = new \Auro\View\Renderer();
        $renderer->setBasePath( VIEWS_PATH . DIRECTORY_SEPARATOR . 'settings' );

        $settingsService
            ->setSomeNamespaceApi( $this )
            ->setValidator( new \Auro\Validation\Validator() )
            ->setConfig( require( CONFIGS_PATH . DIRECTORY_SEPARATOR . 'models_craig_config.php' ) )
            ->setDalApi( new \DalServices\Api() )
            ->setResponse( $fc->getResponse() )
            ->setRenderer( $renderer );
        return $settingsService;
    }

    public function getUsersService() {
        $fc = \Auro\Mvc\Front::getInstance();
        $usersService = new \SomeNamespace\Users();
        $renderer = new \Auro\View\Renderer();
        $renderer->setBasePath( VIEWS_PATH . DIRECTORY_SEPARATOR . 'users' );
        $usersService
            ->setSomeNamespaceApi( $this )
            ->setValidator( new \Auro\Validation\Validator() )
            ->setConfig( require( CONFIGS_PATH . DIRECTORY_SEPARATOR . 'models_craig_config.php' ) )
            ->setAvailableCurrencies( require( CONFIGS_PATH . DIRECTORY_SEPARATOR . 'currencies.php' ) )
            ->setLanguages( require( CONFIGS_PATH . DIRECTORY_SEPARATOR . 'languages.php' ) )           
            ->setPostgersqlPreprocessor( $this->getPostgresqlPreprocessor() )
            ->setResponse( $fc->getResponse() )
            ->setDalApi( new \DalServices\Api() )
            ->setRenderer( $renderer );
        return $usersService;
    }

    public function getVrcommentsService() {
        $fc = \Auro\Mvc\Front::getInstance();
        $vrcommentsService = new \SomeNamespace\Vrcomments();
        $renderer = new \Auro\View\Renderer();
        $renderer->setBasePath( VIEWS_PATH . DIRECTORY_SEPARATOR . 'vrcomments' );
        $vrcommentsService
            ->setSomeNamespaceApi( $this )
            ->setValidator( new \Auro\Validation\Validator() )
            ->setConfig( require( CONFIGS_PATH . DIRECTORY_SEPARATOR . 'models_craig_config.php' ) )
            ->setPostgersqlPreprocessor( $this->getPostgresqlPreprocessor() )
            ->setPaginator( new \Auro\View\Paginator() )
            ->setResponse( $fc->getResponse() )
            ->setDalApi( new \DalServices\Api() )
            ->setRenderer( $renderer );
        return $vrcommentsService;
    }

    public function getVrentalsService() {
        $fc = \Auro\Mvc\Front::getInstance();
        $renderer = new \Auro\View\Renderer();
        $renderer->setBasePath( VIEWS_PATH . DIRECTORY_SEPARATOR . 'vrentals' );
        $vrentalsService = new \SomeNamespace\Vrentals();
        $vrentalsService
            ->setSomeNamespaceApi( $this )
            ->setValidator( new \Auro\Validation\Validator() )
            ->setConfig( require( CONFIGS_PATH . DIRECTORY_SEPARATOR . 'models_craig_config.php' ) )
            ->setPostgersqlPreprocessor( $this->getPostgresqlPreprocessor() )
            ->setPaginator( new \Auro\View\Paginator() )
            ->setDalApi( new \DalServices\Api() )
            ->setRenderer( $renderer )
            ->setResponse( $fc->getResponse() )
            ->setMailConfig( require( CONFIGS_PATH . DIRECTORY_SEPARATOR . 'models_craig_mail.php' ) )
            ->setMailer( new \PHPMailer( true ) );
        return $vrentalsService;
    }

    public function getNoAikService() {
        $fc = \Auro\Mvc\Front::getInstance();
        $renderer = new \Auro\View\Renderer();
        $renderer->setBasePath( VIEWS_PATH . DIRECTORY_SEPARATOR . 'noaik' );
        $AikService = new \SomeNamespace\Noaik();
        $noAikService
            ->setSomeNamespaceApi( $this )
            ->setValidator( new \Auro\Validation\Validator() )
            ->setConfig( require( CONFIGS_PATH . DIRECTORY_SEPARATOR . 'models_craig_config.php' ) )
            ->setPostgersqlPreprocessor( $this->getPostgresqlPreprocessor() )
            ->setPaginator( new \Auro\View\Paginator() )
            ->setResponse( $fc->getResponse() )
            ->setDalApi( new \DalServices\Api() )
            ->setRenderer( $renderer )
            ->setMailConfig( require( CONFIGS_PATH . DIRECTORY_SEPARATOR . 'models_craig_mail.php' ) )
            ->setMailer( new \PHPMailer( true ) );
        return $noAikService;
    }

    public function getTotalauthService() {
        $fc = \Auro\Mvc\Front::getInstance();
        $renderer = new \Auro\View\Renderer();
        $renderer->setBasePath( VIEWS_PATH . DIRECTORY_SEPARATOR . 'totalauth' );
        $totalauthService = new \SomeNamespace\Totalauth();
        $totalauthService
            ->setSomeNamespaceApi( $this )
            ->setValidator( new \Auro\Validation\Validator() )
            ->setRenderer( $renderer )
            ->setResponse( $fc->getResponse() )
            ->setDalApi( new \DalServices\Api() )
            ->setConfig( require( CONFIGS_PATH . DIRECTORY_SEPARATOR . 'models_totalauth_config.php' ) )
            ->setMailConfig( require( CONFIGS_PATH . DIRECTORY_SEPARATOR . 'models_totalauth_mail.php' ) )
            ->setMailer( new \PHPMailer( true ) );
        return $totalauthService;
    }

    public function getQuickmailService() {
        $fc = \Auro\Mvc\Front::getInstance();
        $quickmailService = new \SomeNamespace\Quickmail();
        $quickmailService
            ->setSomeNamespaceApi( $this )
            ->setValidator( new \Auro\Validation\Validator() )
            ->setResponse( $fc->getResponse() )
            ->setMailConfig( require( CONFIGS_PATH . DIRECTORY_SEPARATOR . 'models_quickmail_mail.php' ) )
            ->setMailer( new \PHPMailer( true ) );
        return $quickmailService;
    }
}

?>

有人可以确认这实际上是依赖注入容器,还有什么可以改进的?

4

3 回答 3

1

To me this looks like a collection of methods to instantiate objects needed by the specific API. I don't know that I would consider it dependency injection in and of itself. It is hard to tell though without seeing how this class is actually used. To me, a dependency injection container would basically containe metadata about how to instantiate various classes that implement a common interface.

So a sample set of classes that might interact to achieve dependency injection might look like:

class db_dependency_provider {
    private static $class_map = array(
        'postgres' => 'postgres_abstraction_class',
        'mysql' => 'mysql_abstraction_class',
        'oracle' => 'oracle_abstraction_class'
    }

    public static function get_db_abstraction($type) {
        $class = self::$class_map[$type];
        return new $class();
    }
}

interface db_abstraction_interface {
    public function connect();
    public function query($query);
    // etc.
}

class mysql_db_abstraction implements db_abstraction_interface {
    // actual implementation
}

class postgres_db_abstraction implements db_abstraction_interface {
    // actual implementation
}

class some_class_that_needs_a_db {
    $db = null;
    public function __construct($db) {
        $this->db = $db;
    }
    // other methods
}

// use dependency injection container
$class = new some_class_that_needs_a_db(db_dependency_provider::get_db_abstraction('mysql'));
于 2012-11-29T03:51:40.207 回答
1

I posted an answer to a similar question earlier this year. I believe it should address your concern. How can I use "Dependency Injection" in simple php functions, and should I bother?

It looks like you could also benefit from PHP autoloading, which is also available from the Bart project as well as other open source projects like Composer.

For a general dependency injection primer, you might check out Martin Fowler: http://martinfowler.com/articles/injection.html

于 2012-12-01T02:11:46.460 回答
0

This isn't really dependency injection.

Dependency Injection is when a piece of code relies on some other piece of code. The method signatures and expected return values are known, but the implementation is not. You can totally do this in php but its different from what you have done.

This is what dependency injection might look like(Entirely contrived example):

<?php
class PartnerAttachmentReader implements AttachmentReader{
  private $titleParsingStrategy; 

  private function __construct($titleParsingStrategy){
    $this->titleParsingStrategy = $titleParsingStrategy;
  }

  public static function getInstance($titleParsingStrategy){
    return new PartnerAttachmentReader($titleParsingStrategy);
  }

  public function getTitle($attachment){
    $this->titleParsingStrategy->parseTitle($attachment)
  }

  public function parseAttachment(){
     //Do Some Parsing
  }

} 
?>

What is $titleParsingStrategy? how does it work? unknown. The point is I don't have to care. I can substitute other implementations at my leisure including mock ones at test time.

DI is also useful when dealing with volatile things like disk or network. You can separate the disk and network access in a "dependecy" and test the target of the injection for completeness and correctness without being beholden to network drops or state changes on disk.

于 2012-12-06T21:43:01.573 回答