Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
ueaner committed Mar 22, 2017
0 parents commit 0571cd5
Show file tree
Hide file tree
Showing 22 changed files with 1,123 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# EditorConfig is awesome: http:https://EditorConfig.org
root = true

[*]
end_of_line = lf
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
!.gitkeep
vendor/*
composer.lock
122 changes: 122 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
Soli Dependency Injection Container
------------------

当前项目参考 [Phalcon 框架的事件管理器]实现。

依赖注入容器的目的为了降低代码的耦合度,提高应用的可维护性。

把组件之间的依赖,转换为对容器的依赖,通过容器进行服务管理(创建、配置和定位)。

## 安装

使用 `composer` 安装到你的项目:

composer require soliphp/di

## 使用

容器中常用的四个函数,注册服务时的 `set/setShared` 方法和获取服务时的 `get/getShared` 方法。

服务的注册阶段,仅仅是存储服务定义的格式,并不会调用服务的定义,解析出服务的实例;
而在获取服务(即使用服务)时,对服务的定义进行解析,拿到服务实例。
这样便实现了对服务的延迟加载,避免实例化请求中未用到的服务。

### 注册服务

`服务提供者的格式`,只要是 [call_user_func_array] 允许的格式即可,
也可以是实例化类。

#### 使用匿名函数注册服务:

use Soli\Di\Container;

$di = new Container();

// 注册服务,存储服务的定义
$di->set('some_service', function () {
new SomeComponent;
});

// 注册服务,存储服务的定义
$di->set('some_service', function () use ($di) {
var_dump($di->getServices());
});

将在获取服务时,返回匿名函数的执行结果。

#### 使用类名注册服务

$di->set('some_service', '\SomeNamespace\SomeComponent');

将在获取服务时,返回对应类名的实例化对象。

#### 使用类函数注册服务

$di->set('some_service', [new SomeComponent, 'provider']);

将在获取服务时,返回类函数的执行结果。

__更多服务注册的方式,您可以参考 [call_user_func_array] 允许的格式,整理自己的服务提供方式。__


#### 获取服务

// 获取服务,解析服务定义,并返回服务实例
$service = $di->get('some_service');

### 共享(单例)服务

共享服务意味着让服务以单例模式运行,之后的每次请求都会从容器取到同一个实例。

#### 注册共享服务

当我们使用 `$di->set()` 方法时,可以传入第三个参数为 true,将服务注册为共享服务:

$di->set('some_service', <Some definition>, true);

别名为 setShared,以上代码等同于:

$di->setShared('some_service', <Some definition>);

#### 获取共享服务

当一个服务注册为非共享服务时,我们依然可以通过 getShared 方法获取共享实例:

$service = $di->getShared('some_service');

对于类名无论是否已注册为服务,我们都可以直接通过容器获取到它的共享实例:

$service = $di->getShared('\SomeNamespace\SomeComponent');

这对于我们日常开发中经常用到的单例模式,将格外的方便。

## 示例

[examples] 文件夹下提供了一个类似 [Laravel 框架的服务提供者]的例子,感兴趣的同学可以前去翻看。

运行方法:

$ cd /path/to/soliphp/di/
$ composer install
$ php examples/index.php

## API 参考

[API 参考]

## 测试

$ cd /path/to/soliphp/di/
$ composer install
$ phpunit

## License

MIT Public License


[Phalcon 框架的事件管理器]: https://docs.phalconphp.com/zh/latest/reference/events.html
[call_user_func_array]: http:https://cn2.php.net/call_user_func_array
[API 参考]: http:https://soli-api.aboutc.net/Soli/Di/Container.html
[examples]: examples
[Laravel 框架的服务提供者]: https://laravel.com/docs/5.4/providers
28 changes: 28 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "soliphp/di",
"description": "Soli Dependency Injection Container",
"type": "library",
"keywords": ["di", "container", "DependencyInjection", "soliphp"],
"homepage": "https://github.com/soliphp/di",
"support": {
"issues": "https://github.com/soliphp/di/issues",
"source": "https://github.com/soliphp/di"
},
"license": "MIT",
"authors": [
{
"name": "ueaner",
"email": "[email protected]"
}
],
"require": {
"php": ">=5.5.0",
"psr/container": "^1.0"
},
"autoload": {
"psr-4": {
"Soli\\": "src/"
}
},
"minimum-stability": "dev"
}
65 changes: 65 additions & 0 deletions examples/Soli/Component.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php
/**
* @author ueaner <[email protected]>
*/
namespace Soli;

use Soli\Di\Container;
use Soli\Di\ContainerAwareInterface;

/**
* 组件基类
*
* 通过 $this->{serviceName} 访问属性的方式访问所有注册到容器中的服务
*
* @property \Soli\Di\Container $di
*/
class Component implements ContainerAwareInterface
{
/**
* @var \Soli\Di\Container
*/
protected $container;

public function setDi(Container $di)
{
$this->container = $di;
}

/**
* @return \Soli\Di\Container
*/
public function getDi()
{
if ($this->container === null) {
$this->container = Container::instance() ?: new Container;
}
return $this->container;
}

/**
* 获取容器本身,或者获取容器中的某个服务
*
* @param string $name
* @return \Soli\Di\Container|mixed
*/
public function __get($name)
{
$di = $this->getDi();

if ($di->has($name)) {
$service = $di->getShared($name);
// 将找到的服务添加到属性, 以便下次直接调用
$this->$name = $service;
return $service;
}

if ($name == 'di') {
$this->di = $di;
return $di;
}

trigger_error("Access to undefined property $name");
return null;
}
}
21 changes: 21 additions & 0 deletions examples/Soli/ExampleApp.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Soli;

use Soli\Providers\ConfigServiceProvider;

class ExampleApp extends Component
{
public function registerBaseServiceProviders()
{
(new ConfigServiceProvider)->bind();
}

public function registerConfiguredProviders()
{
$providers = $this->config['providers'];
foreach ($providers as $provide) {
(new $provide)->bind();
}
}
}
35 changes: 35 additions & 0 deletions examples/Soli/Providers/ConfigServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace Soli\Providers;

use Soli\ServiceProvider;

class ConfigServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = true;

/**
* Register the service provider.
*
* @return array
*/
public function register()
{
return require APP_PATH . '/config.php';
}

/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return ['config'];
}
}
45 changes: 45 additions & 0 deletions examples/Soli/Providers/RedisServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

namespace Soli\Providers;

use Soli\ServiceProvider;

class RedisServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = true;

/**
* Register the service provider.
*
* @return \Redis
*/
public function register()
{
// 获取 redis 配置信息
$redisConf = $this->config['redis'];

$client = new \Redis;

$success = $client->connect($redisConf['host'], $redisConf['port']);

$client->setOption(\Redis::OPT_PREFIX, $redisConf['prefix']);
$client->select($redisConf['database']);

return $client;
}

/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return ['redis', 'redis.connection'];
}
}
35 changes: 35 additions & 0 deletions examples/Soli/Providers/TestServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace Soli\Providers;

use Soli\ServiceProvider;

class TestServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = true;

/**
* Register the service provider.
*
* @return string
*/
public function register()
{
return 'This is TestServiceProvider.';
}

/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return ['test', 'test.service', 'test_service'];
}
}
Loading

0 comments on commit 0571cd5

Please sign in to comment.