承接 splot/di 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

splot/di

Composer 安装命令:

composer require splot/di

包简介

Dependency Injection Container by Splot Framework.

README 文档

README

Dependency Injection Container by Splot Framework.

Build Status SensioLabsInsight HHVM Status

Splot Dependency Injection Container is a standalone PHP library that helps with following Inversion of Control and Dependency Injection pattern.

It's a viable alternative to popular Symfony Dependency Injection Component or PHP-DI or any other implementation.

Features

  • Supports both constructor (arguments option) and setter injection (call option).
  • Includes a "parameter container" and parameters can be used inside of various options or as dependencies or include one another.
  • Services can notify (call) other services (e.g. for adding handlers to a collection).
  • Supports factory definitions, where service is created by calling a method on another service.
  • Definitions can extend each other to avoid repeating common formulae (extends option).
  • Allows optional arguments.
  • Reads definitions from YML files.
  • Supports private, read only and aliased services as well as singleton services (default) and not-singleton services (option).
  • Compatible with PHP Container Interoperability project.
  • Container state can be cached to prevent rebuilding it on every request.

TL;DR docs

Get from Composer:

$ composer require splot/di dev-master

Use in PHP:

$container = new \Splot\DependencyInjection\Container();

// register services in PHP
$container->setParameter('debug', true);
$container->register('logger', '\Psr\Log\NullLogger');
$container->register('my_service', array(
    'class' => 'MyClass',
    'arguments' => array('MyService', '1.0', '%debug%'),
    'call' => array(
        array('setLogger', array('@logger'))
    )
));

// load parameters and service definitions from a YML file
$container->loadFromFile(__DIR__ .'/services.yml');

// retrieve a service
$myService = $container->get('my_service');

// retrieve a parameter
$debug = $container->getParameter('debug');

You can check out full list of options and a bunch of examples in the coverall test file: tests/fixtures/coverall.yml.

Installation

You can install Splot DI using Composer.

$ composer require splot/di dev-master

All you need to do to start using it is instantiation:

$container = new \Splot\DependencyInjection\Container();

Using the container

Registering services

  • $container->register('my_service_name', 'MyClass') - easiest if your class doesn't have any other dependencies,
  • $container->register('my_service_name', array('class' => 'MyClass', ...)) - more advanced if you want to add some options (documented below).

Loading from YML

You can also load service definitions and parameters from a YML file. This is highly encouraged as it is much cleaner and much more readable.

$container->loadFromFile(__DIR__ .'/services.yml');

You can check an example YML file here: tests/fixtures/coverall.yml.

The loaded YML file has to be split into two sections: parameters and services (you can omit any of them), e.g.

parameters:
    my_parameter: true

services:
    my_service:
        class: MyApp\MyService

Retrieving services

To retrieve a service from the container just call:

$myService = $container->get('my_service_name');

This will instantiate the service and resolve and inject any dependencies.

Using parameters

You can use container parameters for parametrized common arguments or even class names or other options.

To set a parameter call:

$container->setParameter('debug', true);

And to get a parameter call:

$debug = $container->getParameter('debug');

Parameters can also link to one another:

$container->setParameter('dev_mode', true);
$container->setParameter('debug', '%dev_mode%');

They can also concatenate as strings:

$container->setParameter('version', 1);
$container->setParameter('app_name', 'MyApp ver. %version%');

Whenever referencing a parameter you should surround its name in % signs - one in front and one behind (you can also escape % signs by using them twice - %%).

Referencing other services and parameters

You can inject other services and parameters as dependencies to a service.

When referencing a service either in arguments option or in call option, you have to prepend a @ sign to its name, e.g. @my_service.

When referencing a parameter either in arguments option or in call option, or any other option, you have to surround it in % signs - one in front and one in behind, e.g. %my_parameter.name%.

Options

The following options are available when registering a service, both in PHP and YML file.

Some of them are obsolete when registering already existing object as a service or when using closure as a service recipe.

All examples are using YML notation, but can be translated 1:1 to PHP options array.

class

Class name of the service. Should be a full namespaced class, e.g.

my_service:
    class: MyLib\MyService

Can also be a parameter, if previously defined:

my_service:
    class: %my_service.class%

This is the only required option, except for abstract or factory services.

arguments

List of constructor arguments for the service. Can reference other services (by @ notation) or parameters (by % notation):

my_service:
    class: %my_service.class%
    arguments:
        - MyServiceTitle
        - @logger
        - %debug%

When referencing other services they can be optional - if you add ? sign at the end of the reference then if such service was not found, null will be injected:

my_service:
    class: %my_service.class%
    arguments:
        - @logger?

In the example above, if logger service does not exist then null will be put in its place.

call

List of service methods that should be called on the service right after it has been instantiated. Each call entry is an array where index 0 is method name and index 1 is an array of the method arguments.

You can also reference parameters or other services here in method arguments, e.g.:

my_service:
    class: %my_service.class%
    call:
        - [setName, ["My Service Title"]]
        - [setVersion, ["1.0", "stable"]]
        - [setLogger, "@logger"]
        - [setDebug, "%debug%"]

If a single argument is given to the method, then index 1 or the call array can be that argument and not an array (like in two last lines in the above example).

factory_service, factory_method, factory_arguments

If your service needs to be a product of a factory then you can specify what method to call on what service with what arguments to get that service.

my_factory:
    class: MyApp\MyServicesFactory

my_service:
    factory_service: my_factory
    factory_method: provideService
    factory_arguments:
        - @logger?
        - %debug%

When getting my_service the method ::provideService() of a service my_factory will be called with the specified arguments and the result of that method call will be returned as the service. It will also be cached as the service instance, unless singleton option will be set to false in which case every request for my_service will result in the above method call.

factory

Shorthand option for factory_service, factory_method and factory_arguments options.

An array where index 0 = factory_service, 1 = factory_method and 2 = factory_arguments (optional).

my_service:
    factory: ['@my_factory', 'provideService', [@logger?, %debug%]]

notify

Unique feature of Splot DI is ability for services to notify other services. This is an alternative to tagging and writing compiler passes in Symfony DI Component.

notify is essentially a method call on another service that may or may not exist.

my_services_collection:
    class MyApp\MyServicesCollection

my_service.one:
    class: MyApp\MyService
    arguments: ['one']
    notify:
        - [my_services_collection, addService, ["service_one", "@"]]

my_services.two:
    class: MyApp\MyService
    arguments: ['two']
    notify:
        - [my_services_collection, addService, ["service_two", "@"]]

With the above definition, retrieving the service my_services_collection will also cause services my_service.one and my_service.two to be instantiated and injected to my_services_collection by calling ::addService() method on my_services_collection with specified arguments for each of the injected services. The special character @ in this case refers to the service itself and is a shorthand for @my_service.one or @my_service.two appropriately.

You can use @ sign to reference the service itself in arguments of a notification or @= to reference name of the service.

However, retrieving the service my_service.one itself will not cause my_services_collection to be instantiated. But later, if my_services_collection is instantiated then my_service.one will be appropriately injected to it.

The sender service (e.g. my_services.two in the example above) will only be instantiated if you reference it by @ in notification argument. Otherwise it's subject to normal instantiation strategy.

A service can notify indefinite number of other services. It can also try to notify services that don't exist - in which case no exception is thrown nor any error raised.

See "Common Recipes" section below for use cases of this feature.

abstract

Set to true if you want to mark this service as not instantiable. This is useful when you want to create a common service recipe that will be reused by other services.

Abstract services don't need to specify a class.

extends

Specify "parent" definition of a service. This service will inherit almost all options (those that make sense, e.g. abstract option is not inherited) from the service it extends and can also overwrite any of them.

my_service:
    class: MyApp\MyService
    arguments: ["my_app", "1.0", %debug%, @logger?]
    call:
        - [setSomething, true]
        - [incrementCounter]

your_service:
    class: YourApp\YourService
    extends: my_service

your_service service will be instantiated as an object of class YourApp\YourService but with the same constructor arguments and method calls as my_service.

singleton

All services in Splot DI are singletons by default. Set singleton option to false if you want the container to always return a new instance.

my_service:
    class: %my_service.class%
    singleton: false

aliases

When registering a service you can also register a bunch of aliases for it. You will be able to use them when retrieving the service.

my_service:
    class: %my_service.class%
    aliases:
        - my_service.alias
        - my_fake_service
        - your_service

alias

You can register a service as an alias to another service. It will simply make the container refer to that service also by its new name.

my_service:
    class: %my_service.class%

my_service.alias:
    alias: my_service

private

If you don't want a service to be directly retrievable from the container, mark it as private. You will not be able to get it using $container->get() method, but you will be able to use it as a dependency to another service.

my_service:
    class: %my_service.class%
    private: true

read_only

If you want to make sure that your service will not be overwritten by another service then mark it as read only.

my_service:
    class: %my_service.class%
    read_only: true

Tips

Compact definition

If your service is just an instance of a class that doesn't get any constructor arguments and you don't need to set any other options, then this:

my_service:
    class: MyApp\MyService

can be reduced to this:

my_service: MyApp\MyService

Compact factory definition

If your service is a product of a factory and you don't neeed to set any other options, then this:

my_service:
    factory: ['@my_factory', 'provideService', [@logger?, %debug%]]

can be reduced to this:

my_service: ['@my_factory', 'provideService', [@logger?, %debug%]]

Common Recipes

Here are some common recipes for reuse or better understanding of Splot DI.

Using "notify" option for adding log handlers

Using notify option can give you a lot of power and flexibility.

Best use case for it is when you have a facade service with a simple API that takes a dynamic number of other classes that handle the input in various ways. For example a simple logger with many log handlers (as in Monolog):

logger:
    class: Monolog\Logger

logger.handler.stream:
    class: Monolog\Handler\StreamHandler
    arguments:
        - "path/to/your.log"
        - 300
    notify:
        - ["logger", "pushHandler", ["@"]]

logger.handler.slack:
    class: Monolog\Handler\SlackHandler
    arguments: ["%slack.api.token%", "%slack.log_channel%"]
    notify:
        - ["logger", "pushHandler", ["@"]]

Now, when you retrieve the logger service it will automatically have StreamHandler and SlackHandler injected. And nothing stops other parts of your application (e.g. other modules or "bundles") to add their own handlers.

Contribute

Issues and pull requests are very welcome! When creating a pull request please include full test coverage to your changes.

splot/di 适用场景与选型建议

splot/di 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 1.4k 次下载、GitHub Stars 达 0, 最近一次更新时间为 2014 年 08 月 30 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「container」 「dependency」 「di」 「ioc」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 splot/di 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 splot/di 我们能提供哪些服务?
定制开发 / 二次开发

基于 splot/di 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 1.4k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 0
  • 依赖项目数: 1
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 1
  • Forks: 1
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2014-08-30