最近在学习 java 。 看java 入门到精通 。在反射部分 突然对以前不懂的 依赖注入 豁然开朗
依赖注入 就是通过反射 去获取对象中需要的参数 类
下面是模仿laravel 实现过程 。比较 low
原创 转载请注明出处
https://github.com/Childdreams/laravelIoc 源码地址
<?php
/**
* 依赖注入取决的 就是 容器和反射 两个部分
* 可以考虑一个服务提供者
* 然后 在服务提供者进行注册
* 服务提供者 在生命周期内
* 进行注册 或者其他的操作
* 需要实现接口
* 接口 register 为注册 handle 为执行 boot 为监听
*/
namespace app;
use app\interfaces\RequestInterface;
use app\interfaces\SendSmsInterface;
/**
* 实现接口
*/
class Request implements RequestInterface
{
public $id = 0 ;
}
class SendSmsService implements SendSmsInterface
{
public $name = "This is sendSmsSevice ";
}
namespace app\interfaces;
/**
* 接口类
* 解耦使用
*/
interface RequestInterface{}
namespace app\interfaces;
interface SendSmsInterface {}
namespace bpp;
/**
* 容器类
*/
class Container
{
public $register = [];
public function register(array $bind){
foreach($bind as $concrete){
if($concrete !instanceof Closure){
throw new Exception();
}
}
$this->register = array_merge($this->register , $bind) ;
}
}
namespace cpp;
use app\interfaces\RequestInterface;
use app\interfaces\SendSmsInterface;
/**
* 控制器
*/
class UserController
{
public function __construct()
{
}
public function test(RequestInterface $request , SendSmsInterface $sendSmsService){
var_dump($request->id);
var_dump("this is 依赖注入");
var_dump($sendSmsService->name);
}
}
namespace test;
use bpp\Container;
//实例化容器
$api = new Container();
//将依赖注册到容器 , 此处用 接口模式 是为了 解耦合
$api->register([
\app\interfaces\RequestInterface::class => \app\Request::class
]);
$api->register([
\app\interfaces\SendSmsInterface::class => \app\SendSmsService::class
]);
// 模仿路由
$router = "cpp\UserController@test";
$routers = explode("@",$router);
// 将 控制器 反射 出来
$ref = (new \ReflectionClass($routers[0]));
// 获取 控制器的 方法 里面的参数
$refs = $ref->getMethod($routers[1])->getParameters();
$inject = [];
foreach ($refs as $re){
//获取参数的类
$class = $re->getClass()->name;
// 在容器查询 是否注册过
if (array_key_exists($class , $api->register)){
// 获取 容器内注册的方法
$class = $api->register[$class];
//浅显易懂
$classes = $ref->newInstance();
$name = $routers[1];
$inject[] = new $class();
}else {
throw new \Exception("bug");
}
}
(new $classes())->{$name}(...$inject);
依赖注入
-
理解
依赖注入的实现方式就是 将需要注入的服务注册到容器内, 当路由访问一个控制器的时候 利用反射
ReflectionClass
去获取需要注入的服务。然后将服务进行实例化注入代码实现部分
$router = "cpp\UserController@test"; $routers = explode("@", $router); // 将 控制器 反射 出来 $ref = (new \ReflectionClass($routers[0])); // 获取 控制器的 方法 里面的参数 $refs = $ref->getMethod($routers[1])->getParameters(); $inject = []; foreach ($refs as $re) { //获取参数的类 $class = $re->getClass()->name; // 在容器查询 是否注册过 if (array_key_exists($class, $app->register)) { // 获取 容器内注册的方法 $class = $app->register[$class]; //浅显易懂 $name = $routers[1]; $inject[] = new $class(); } else { throw new \Exception("bug"); } } $classes = $ref->newInstance(); // == new $ref call_user_func_array([$classes , $name] , ...$inject) ;
至于怎么注册到容器 laravel 的写法是 服务提供者。 将服务提供者注册到
见
/config/app.php
将服务提供者携带的 服务注册到 容器中
bootstrap/app.php
line 23baofeng\Demo\Kernel\Kernel@reisterServiceProvider
门面模式
门面模式的核心内容 依旧是将门面模式的注入到容器之中 。在正常的 门面模式直接返回注入时候的key , 通过 __callstatic 去容器中查询
baofeng\Demo\Facaders\Facader
迭代器 IteratorAggregate
laravel 中 db 等 对象进行foreach 循环时候 ,循环出来的只是它想让你循环的东西 这时候就用到了
baofeng\Demo\Https\Request
baofeng\Demo\Iterators\MyIterator
详细的注释在 baofeng\Demo\Iterators\MyIterator
中