是否应该仅通过接口引用依赖关系?

时间:2015-09-16 07:22:01

标签: php dependency-injection ioc-container

我一直致力于从程序转换 - > oop几个月了。我决定避免跳进框架。我不想依赖幕后魔术,所以在业余时间我决定转换旧项目并构建一个小框架来运行它。对于教程,我主要转向google laravel / laracast教程,因为它是最容易找到的信息。我会说我正处于我的框架和#39;是一个较小的简化(通过这个我的意思不是功能包装/复杂)版本的laravel。我还没有围绕symfony / laravel提供的所有东西,但随着我的进步,事情开始变得咔哒咔哒。目前,我相信一旦我完成旧项目的转换,我将与laravel合作。

好的,现在。我不断怀疑的一件事是依赖注入。我发现所有/大多数注射器通过构造使用类型提示注入。我开始使用静态注册表并慢慢迭代,直到我有以下类

<?php

/**
 *------------------------------------------------------------------------------
 *
 *  Framework Container - Class Builder + Injector + Container
 *
 *  The Container Is Responsible For Dependency Injection Via Class Constructors
 *  Through Abstract 'Alias' Keys Defined Within The Class. It Is Also Used To
 *  Hold Various Data Including Closures, Or Cached Object Instances.
 *
 */
namespace eSportspCMS;
use \eSportspCMS\Helpers\Support\Base;
use \eSportspCMS\Contracts\Container as ContainerContract;

class Container extends Base implements ContainerContract {


    /**
     *  Alias Container
     *  Contains Alias Keys Defining Classes To Instantiate     See $this->make()
     */
    private $aliases    = [];

    /**
     *  Binding Container
     *  Contains Custom Closure Bindings                        See $this->make()
     */
    private $bindings   = [];


    /**
     *  Cache Container
     *  Contains Previously Instantiated Classes                See $this->make()
     */
    private $cache      = [];

    /**
     *  Closure Container
     *  Contains Custom Closures To Avoid Hardcoding Within Class
     */
    private $closures   = [];


    /**
     *  Class Dependency Key
     *  Public Var Within Classes Defining The Dependency List
     */
    private $varkey     = 'dependencies';


    /**
     *  Define Class Dependency Key
     *
     *  @param string $varkey           Class Dependency Key
     */
    public function setvarkey($varkey)  {
        $this->varkey = $varkey;
    }


    /**
     *  Set Data Within Containers
     *
     *  @param string $key              Key To Use When Setting Container Var
     *  @param mixed  $value            Value To Use When Setting Container Var
     */
    public function alias($key, $value) {   $this->aliases[$key]    = $value;   }
    public function bind ($key, $value) {   $this->bindings[$key]   = $value;   }
    public function cache($key, $value) {   $this->cache[$key]      = $value;   }


    /**
     *  Add New Closure Within Container
     *
     *  @param string   $key            Closure Key
     *  @param callable $value          Callable Function
     */
    public function closure($key, callable $value) {
        if (method_exists($this, $key)) {
            throw new \Exception($key . ' Already Exists As A Method. Which
            Means This Closure Would Not Be Accessible If Set!');
        }
        $this->closures[$key] = $value;
    }


    /**
     *  Access Closure If Method Being Called Does Not Exist
     *
     *  @param  string $key             Closure Key
     *  @param  array  $params          Params To Pass To Closure
     *  @return mixed                   Closure Response If Exists
     */
    public function __call($key, $params = []) {
        if (isset($this->closures[$key]) && is_callable($this->closures[$key])) {
            return call_user_func_array($this->closures[$key], $params);
        }
        return false;
    }


    /**
     *  Create New Class Instance
     *
     *  Forces $this->make() To Instantiate A New Class Instead Of Returning
     *  A Cached Instance.
     *
     *  @see                            $this->make() Comments
     */
    public function makeNew($class, $params = []) {
        return $this->make($class, $params, false, true);
    }


    /**
     *  Pull Class From Cache Based On Key, Call Binding Or Instantiate Class
     *  Resolve Dependencies And Pass Via Construct.
     *
     *  @param  string $key             Alias Key | Binding Key | Class To Make
     *  @param  array  $params          Additional Params Passed Via Constructor
     *  @param  bool   $cache           Determines If Class Can Be Cached
     *  @param  bool   $new             Forces New Instance Of Object
     *  @return object                  Instantiated Or Cached Object
     */
    public function make($key, $params = [], $cache = true, $new = false) {

        /**
         *  Params Indicate Cached Instance Can Be Used
         */
        if (!$new && isset($this->cache[$key])) {
            return $this->cache[$key];
        }


        /**
         *  If Binding Is Defined And Key Matches Return It Instead Of Building
         *  The Class Directly. Replace Params With App
         */
        if (isset($this->bindings[$key]) && is_callable($this->bindings[$key])) {
            $instance   = call_user_func_array($this->bindings[$key], $this->make('app'));
            $cache      ? $this->cache($key, $instance) : '';
            return $instance;
        }


        /**
         *  Cache And Binding Statement Failed! Attempt To Build Class.
         *
         *  If      Class Exists Instantiate, Resolve/Pass Dependencies,
         *          Cache ( If Allowed ), And Return.
         *
         *  Else    Throw Exception!
         */
        $classname = isset($this->aliases[$key]) ? $this->aliases[$key] : $key;
        if (class_exists($classname)) {
            $instance   = new $classname($this->resolveDependencies($classname, $params));
            $cache      ? $this->cache($key, $instance) : '';
            return $instance;
        }


        // All Statements Failed! Class Couldn't Be Created
        throw new \Exception('Container Could Not Create Class: ' . $classname);
    }


    /**
     *  Resolve/Build Class Dependencies
     *
     *  Dependencies Cascade To Simplify/Unify Dependency Setting Within Grouped
     *  Classes. ( Classes Like Controllers Which Would Extend Base Controller )
     *
     *  @param  string $classname       Class Being Instantiated
     *  @param  array  $params          Additional Params Being Passed
     *  @return array                   Assoc Array With Class Dependencies
     */
    private function resolveDependencies($classname, $params = []) {

        // Define Class Tree
        $classes    = array_reverse((array) class_parents($classname));
        $classes[]  = $classname;

        // Retrieve Class Dependencies From Tree ( Alias Keys ) & Build
        $dependencies = $this->dependencies($classes);
        foreach ((array) $dependencies as $dependency) {
            $dependencies[$dependency] = $this->make($dependency);
        }

        // Return Merged Dependencies
        return array_merge($dependencies, $params);
    }


    /**
     *  Retrieve Class Dependency List ( Alias Keys )
     *
     *  @param  array $classes          Array Containing Classes
     *  @return array                   Class Dependencies ( Alias Keys )
     */
    private function dependencies($classes = []) {
        if (!$classes) {    return;    }

        $aliases = [];
        foreach ((array) $classes as $c) {
            $vars = get_class_vars($c);

            if (isset($vars[$this->varkey])) {
                $aliases = array_merge($aliases, $vars[$this->varkey]);
            }
        }
        return array_unique($aliases);
    }
}

我如何使用 框架应用程序类将扩展容器。在应用程序引导期间,将加载依赖项的别名键(我使用laravel的相同配置设置 - 从config目录中的返回数组加载配置)当使用容器实例化类时,它将搜索依赖项列表&#39; varkey& #39;,它将迭代并合并父类依赖关系(对于分组依赖关系,如模型 - 模型扩展基础模型),然后它将构建依赖关系树,实例化类和缓存(如果允许)。依赖关系通过构造作为assoc数组传递给类[&#39;别名&#39; =&GT;宾语]。扩展&#39; \ helpers \ support \ base&#39;的类class具有为它们设置的依赖项。基础构造类使用别名键作为类​​键遍历数组,设置类中的依赖关系。

关注 当看到其他注射器时,我看到使用了类型,我不确定这是否是由于这种类型的依赖注入的缺陷,我还没有看到。我认为别名键的方式是&#39;接口&#39;最重要的是,所使用的依赖项实现了契约,所以当我改变类时,契约仍然定义了类的要求。

问题 有理由: *偏离使用这个注射器?为什么? (我不是在寻找&#34;不要重新发明轮子&#34;答案我想要进一步了解我并了解我在做什么) *实施服务提供商&#34; laravel教程&#34;什么时候用?目前我操纵构造中的依赖项(如果我需要来自依赖项的特定数据,我使用getters / setters来检索数据并在类中设置)

我是否需要为我创建的每个类(包括控制器)创建一个契约/接口,或者是仅在依赖项的类上使用的接口? (我发现了很多混合的反馈,所以我被撕裂了,以为我会把它扔进去)

类示例 以下类是我的404错误控制器。它是其他控制器中使用的依赖项之一,因为我有依赖于db数据(用户)的页面,如果用户不存在,我会显示404错误。

<?php

/**
 *------------------------------------------------------------------------------
 *
 *  Error Controller
 *
 */
namespace Application\Controllers;
use \eSportspCMS\Helpers\Support\Base;

class Error extends Base {
    public $dependencies = ['http', 'log', 'metadata', 'view'];


    /**
     *  404 Error Page Not Found
     */
    public function display404($msg = '', $params = []) {

        // If Msg Present Log Error
        !$msg ?: $this->log->error($msg, $params);

        // Define 404 HTTP Header
        $this->http->set('header', 'HTTP/1.1 404 Not Found');

        // Set 404 Sitetitle
        $this->metadata->sitetitle('error', 'display404');


        // Return View File + View Data
        return $this->view->display('www/custompages', $this->custompage->info(1));
    }
}

提前感谢您提供所有反馈。

0 个答案:

没有答案
相关问题