xou816/silex-autowiring

一个用于在 Silex 中自动配置服务的工具。

0.1 2017-10-15 10:50 UTC

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 传递一个参数数组,这些参数将按顺序传递,如果无法将参数解析为服务。

控制器注入

您可以直接在控制器中注入配置好的服务,而无需调用 providername,因为配置好的服务可以直接注入到控制器中,与常规的 RequestApplication 对象一起。

$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 类似,但注入的是普通值。

警告:注入到属性中的值仅在构建之后才可用。

注入解析器

您可能不喜欢 Injectableconfigure 处理名称的方式(从蛇形命名法到驼峰命名法)。通过提供自定义实现(例如使用 wire)可以调整这种行为。通过扩展 SilexAutowiring\Injectable\AbstractCompositeKeyResolver,可以使处理如 foo_options.baz 这样的标识符变得更容易。

您还可以直接将 SilexAutowiring\Injectable\IdentityResolverwire 到您的应用中,以使用更简单的解析机制(无需更改大小写风格)。

实验性

您还可以使用 SilexAutowiring\Traits\AutowireSilexAutowiring\Traits\Autoconfigure 特性来替代调用 wireconfigure

但是,这并不完全等效,并且在性能上可能更差。

class Foo {
    use Autowire;
}
class Bar {
    use Autowire;
    public function __construct(Foo $foo) {
        $this->foo = $foo;
    }
    public function greet() {
        return 'Hello!';
    }
}