Silex:如何连接多个第 3 方库?
Silex: how to connect several 3rd-party libraries?
我正在尝试将第 3 方工具注入我在 Silex 中的自定义 class。然后我计划在某个时候用另一个库替换这个工具。为了符合 DI 原则,为了分离我的 class 和库,我将指定这些工具必须实现的接口。并在我的自定义 class 构造函数中键入提示接口。这将帮助我避免对 class 进行任何更改。像这样
class MyCustomClass
{
private $tool;
public function __construct(MyCustomInterface $tool)
{
$this->tool = $tool;
}
}
要注册那些第 3 方库,我必须为它们中的每一个创建服务提供商。那么我似乎需要某种适配器来使这些工具符合合同 MyCustomInterface 状态。事实证明,对于每个第 3 方工具,我必须管理 2 个额外的 classes(提供者和适配器)。
我的问题是:
我的 DI 概念是否完全正确?
是否可以简化此解决方案?
Silex 能否通过 'adapters' 处理这种情况?
据我所知,您的 DI 概念是正确的。如果您不想每次更改库时都重构整个代码(以及使用您的库的代码),那么适配器就是您要走的路:您定义一个特定的 API 接口,每个适配器必须实施。通过这种方式,您的代码可以安全地调用接口方法,而无需了解背后的实现。所以恕我直言,这是要走的路,你又来了(但我认为你在 Silex 上下文中的解决方案可以简化,是的,Silex 可以管理这个,任何其他现代框架也应该如此)。
为了简化您提出的解决方案,我不会为每个实施创建不同的提供程序。提供者将您的库与 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);
});
此解决方案不太优雅但更简单(您需要更改为每个适配器创建服务的代码)。
我正在尝试将第 3 方工具注入我在 Silex 中的自定义 class。然后我计划在某个时候用另一个库替换这个工具。为了符合 DI 原则,为了分离我的 class 和库,我将指定这些工具必须实现的接口。并在我的自定义 class 构造函数中键入提示接口。这将帮助我避免对 class 进行任何更改。像这样
class MyCustomClass
{
private $tool;
public function __construct(MyCustomInterface $tool)
{
$this->tool = $tool;
}
}
要注册那些第 3 方库,我必须为它们中的每一个创建服务提供商。那么我似乎需要某种适配器来使这些工具符合合同 MyCustomInterface 状态。事实证明,对于每个第 3 方工具,我必须管理 2 个额外的 classes(提供者和适配器)。
我的问题是:
我的 DI 概念是否完全正确?
是否可以简化此解决方案?
Silex 能否通过 'adapters' 处理这种情况?
据我所知,您的 DI 概念是正确的。如果您不想每次更改库时都重构整个代码(以及使用您的库的代码),那么适配器就是您要走的路:您定义一个特定的 API 接口,每个适配器必须实施。通过这种方式,您的代码可以安全地调用接口方法,而无需了解背后的实现。所以恕我直言,这是要走的路,你又来了(但我认为你在 Silex 上下文中的解决方案可以简化,是的,Silex 可以管理这个,任何其他现代框架也应该如此)。
为了简化您提出的解决方案,我不会为每个实施创建不同的提供程序。提供者将您的库与 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);
});
此解决方案不太优雅但更简单(您需要更改为每个适配器创建服务的代码)。