xou816 / silex-autowiring
一个用于在 Silex 中自动配置服务的工具。
Requires
- php: >=5.5
- silex/silex: v2.*
Requires (Dev)
- phpunit/phpunit: ^5.0
- symfony/browser-kit: ^3.3
This package is not auto-updated.
Last update: 2024-09-20 22:07:58 UTC
README
自动配置所有服务!适用于 Silex。
要求
PHP 5.5+
安装
通过 Composer: composer require xou816/silex-autowiring。
use SilexAutowiring\AutowiringServiceProvider; // ... $app->register(new AutowiringServiceProvider());
服务将以 $app['autowiring'] 的形式可用。
使用方法
基础
构造函数注入
调用 wire 方法,让自动配置服务创建实例。
class Foo {} class Bar { public function __construct(Foo $foo) { $this->foo = $foo; } public function greet() { return 'Hello!'; } } $app['autowiring']->wire(Foo::class); $app['autowiring']->wire(Bar::class);
可以使用 $app['autowiring']->provider(Bar::class) 查找 Bar 的实例。如果您只需要服务名称,请使用 name 方法。
Bar 的每个依赖都必须为 AutowiringService 所知!
您可以为 wire 传递一个参数数组,这些参数将按顺序传递,如果无法将参数解析为服务。
控制器注入
您可以直接在控制器中注入配置好的服务,而无需调用 provider 或 name,因为配置好的服务可以直接注入到控制器中,与常规的 Request 或 Application 对象一起。
$app->get('/', function (Bar $bar) { return $bar->greet(); });
闭包注入
您还可以使用 invoke 在闭包中注入服务。
$fun = function(Foo $foo, $arg) { $foo->bar($arg); }; $app['autowiring']->invoke($fun, ['bar']); // Calls $foo->bar('bar'), where $foo has class Foo
如果您想延迟执行闭包(即获取一个闭包),请使用 partial 代替。
$fun = function(Foo $foo, $arg) { $foo->bar($arg); }; $newfun = $app['autowiring']->partial($fun); $newfun('bar'); // Calls $foo->bar('bar'), where $foo has class Foo
接口
自动配置服务还可以根据接口而不是类注入服务。如果有多个服务实现相同的接口,则最后配置的服务将被使用。
interface GreeterInterface { public function greet(); } class PoliteGreeter implements GreeterInterface { public function greet() { return 'Hello!'; } } $app['autowiring']->wire(PoliteGreeter::class); class RudeGreeter implements GreeterInterface { public function greet() { return '...'; } } $app['autowiring']->wire(RudeGreeter::class); $app->get('/', function(GreeterInterface $greeter) { return $greeter->greet(); // '...' });
这对于轻松切换接口的实现非常有用。
注入其他服务
公开内置服务
如果您想使用与 Silex 一起提供的或提供者服务,您可以使用 expose 方法。例如
$app->register(new DoctrineServiceProvider()); // registers a 'db' service $app['autowiring']->expose('db'); // ... class DAO { public function __construct(\Doctrine\DBAL\Connection $db) { /**/ } } $app['autowiring']->wire(DAO::class); // will work just fine!
AutowiringService 本身是公开的,因此可以注入!
自定义服务提供者
您可以使用 provide 控制实例的创建方式。
$app['autowiring']->provide(Foo::class, function($app, Bar $bar) { return new Foo($bar); });
注入任何服务
您还可以注入任何其他服务,甚至普通 PHP 对象(对于这些对象,无法使用类型提示),例如数组或整数,只要它们在 Pimple 容器中可用。
为了做到这一点,请向 SilexAutowiring\Injectable\Injectable 添加一个依赖。
$app['foo_options'] = array('bar' => true); $app['foo_options.baz'] = false; class Foo { public __construct(Injectable $fooOptions) { $this->bar = $fooOptions->get()['bar']; // true $this->baz = $fooOptions->get()['baz']; // false } } $app['autowiring']->wire(Foo::class);
自动配置服务知道如何注入正确的服务,因为它从构造函数参数的名称(例如,将 fooOptions 从驼峰式转换为蛇形)推断出服务名称。由于必须将 Injectable 的实例传递给构造函数,您可以通过调用 get 来检索实际的服务。
如果您想注入配置数组,您可以使用 SilexAutowiring\Injectable\Configuration,它的工作方式与 Injectable 完全一样(两者都实现了 SilexAutowiring\Injectable\InjectableInterface),但它具有数组访问功能。
// ... class Foo { public __construct(Configuration $fooOptions) { $this->bar = $fooOptions['bar']; // true $this->baz = $fooOptions['baz']; // false } }
属性注入
无法依赖于类型提示来在属性上注入服务。因此,此功能主要用于配置。
$app['fooconfig'] = array('bar' => true); $app['fooconfig.baz'] = false; class Foo { private $bar; private $baz; } $app['autowiring']->wire(Foo::class); $app['autowiring']->configure(Foo::class, 'fooconfig');
它解析名称的方式与 Injectable 类似,但注入的是普通值。
警告:注入到属性中的值仅在构建之后才可用。
注入解析器
您可能不喜欢 Injectable 和 configure 处理名称的方式(从蛇形命名法到驼峰命名法)。通过提供自定义实现(例如使用 wire)可以调整这种行为。通过扩展 SilexAutowiring\Injectable\AbstractCompositeKeyResolver,可以使处理如 foo_options.baz 这样的标识符变得更容易。
您还可以直接将 SilexAutowiring\Injectable\IdentityResolver 类 wire 到您的应用中,以使用更简单的解析机制(无需更改大小写风格)。
实验性
您还可以使用 SilexAutowiring\Traits\Autowire 和 SilexAutowiring\Traits\Autoconfigure 特性来替代调用 wire 和 configure。
但是,这并不完全等效,并且在性能上可能更差。
class Foo { use Autowire; } class Bar { use Autowire; public function __construct(Foo $foo) { $this->foo = $foo; } public function greet() { return 'Hello!'; } }