Silex:如何连接多个第三方库?

时间:2015-12-11 07:54:47

标签: php dependency-injection silex

我正在尝试将第三方工具注入Silex中的自定义类。然后我计划在某个时候用另一个库替换这个工具。为了符合DI原则,为了解耦我的类和库,我将指定这些工具必须实现的接口。并在我的自定义类构造函数中键入提示接口。这将有助于我避免对我的课程进行任何更改。喜欢这个

for(i in 1:length(a$age))
{
    ifelse(a$age<17, a$age_group<-"mid", 
                     ifelse(a$age<20, a$age_group<-"high", 
                                      ifelse(a$age<24, a$age_group<-"univ", 
                                                       a$age_group<-"worker")))
}

要注册这些第三方库,我必须为每个库创建服务提供商。然后我似乎需要某种适配器来使这些工具符合MyCustomInterface所规定的合同。事实证明,每个第三方乐器我必须管理2个额外的类(提供者和适配器)。

我的问题是:

  • 我的DI概念完全正确吗?

  • 是否可以简化此解决方案?

  • Silex是否能够通过'适配器'来管理这种情况?

1 个答案:

答案 0 :(得分:1)

据我所知,你的DI概念正确。如果您不想在每次更改库时重构整个代码(以及使用您的库的代码),那么适配器就是最佳选择:您可以使用每个适配器必须实现的接口定义特定的API 。通过这种方式,您可以安全地调用接口方法,而无需了解后面的实现。所以恕我直言,这是要走的路,你再次来到这里(但我认为你的Silex环境中的解决方案可以简化,是的,Silex可以管理这个,任何其他现代框架也应如此)。 / p>

为了简化您提出的解决方案,我不会为每个实现创建不同的提供程序。提供程序将您的库与Silex绑定在一起,您只需告诉提供程序必须使用哪个适配器(实现),您可以使用参数执行此操作(请参阅代码示例末尾的注释)。所以我会选择这样的东西:

<?php

namespace Acme;

use Silex\Application;
use Silex\ServiceProviderInterface;
use Acme\MyCustomInterface; // This is your library interface

class MyCustomLibraryServiceProvider implements ServiceProviderInterface
{
    public function register(Application $app)
    {
        $app['some_dependency'] = $app->protect(function() use ($app) {
           // do whatever to create a new instance of this dependency
        });

        $app['another_dependency'] = $app->protect(function() use ($app) {
           // do whatever to create a new instance of this dependency
        });

        $app['my_service'] = $app->protect(function () use ($app) {
            // assuming your adapter has 2 dependencies.
            $myService = new $app['my_service_class']($app['some_dependency'], $app['another_dependency']);

            if (!$myService instanceof MyCustomInterface) {
                throw new \RuntimeException("The 'my_service_class' parameter must implement MyCustomInterface!");
            }

            return $myService;
        });
    }

    public function boot(Application $app)
    {
    }
}

然后,当您创建$ app实例时(可以根据需要创建尽可能多的适配器):

<?php
//...
use Acme\MyCustomLibraryServiceProvider;

//...
$app->register(new MyCustomLibraryServiceProvider(), [
    'my_service_class' => "Acme\MyCustomLibraryAdapter1"
]);

请注意,此解决方案假定每个适配器都具有相同的依赖项。如果不是这种情况,您需要为每个适配器创建另一个提供商,但如果您不想这样做,请继续阅读: - )

如果您想进一步简化此操作,请考虑到您需要创建提供商。如果您的库没有依赖项或只有1或2,您可以直接在创建应用程序实例的同一文件中创建服务(恕我直言,只有在创建服务的代码很重时,提供程序才有用):

<?php
//...
use Silex\Application;
use Acme\MyCustomLibraryAdapter1;

$app = new Application();
//...
$app['my_service'] = $app->protect(function() use ($app) {
  $dep1 = new WhatEver();

  return new MyCustomLibraryAdapter1($dep1);
});

此解决方案不太优雅,但更简单(您需要更改为每个适配器创建服务的代码)。