依赖注入demo
让我们看一个例子:
class UserProvider{
protected $connection;
public function __construct(){
$this->connection = new Connection;
}
public function retrieveByCredentials( array $credentials ){
$user = $this->connection
->where( 'email', $credentials['email'])
->where( 'password', $credentials['password'])
->first();
return $user;
}
}
如果你要测试或者维护这个类,你必须访问数据库的实例来进行一些查询。为了避免必须这样做,你可以将此类与其他类进行 解耦 ,你有三个选项之一,可以将 Connection 类注入而不需要直接使用它。
将组件注入类时,可以使用以下三个选项之一:
构造方法注入
class UserProvider{
protected $connection;
public function __construct( Connection $con ){
$this->connection = $con;
}
}
Setter 方法注入
同样,我们也可以使用 Setter 方法注入依赖关系:
class UserProvider{
protected $connection;
public function __construct(){
...
}
public function setConnection( Connection $con ){
$this->connection = $con;
}
}
接口注入
interface ConnectionInjector{
public function injectConnection( Connection $con );
}
class UserProvider implements ConnectionInjector{
protected $connection;
public function __construct(){
...
}
public function injectConnection( Connection $con ){
$this->connection = $con;
}
}
当一个类实现了我们的接口时,我们定义了 injectConnection 方法来解决依赖关系。
优势
现在,当测试我们的类时,我们可以模拟依赖类并将其作为参数传递。每个类必须专注于一个特定的任务,而不应该关心解决它们的依赖性。这样,你将拥有一个更专注和可维护的应用程序。
部分代码:
index.php
<?php
spl_autoload_register('autoLoad', true, true);
use a\TestA;
use b\TestB;
// 要调用的类
$class = TestA::class;
// 调用类中的方法
$method = 'hello';
$obj = createObj($class);
$methodParam = parseMethod(TestA::class, $method);
call_user_func_array([$obj, $method], $methodParam);
/**
* 根据类名 创建对象 并自动注入
* @param string $className
* @return object
* @throws ReflectionException
*/
function createObj(string $className): object
{
$reflction = new ReflectionClass($className);
$paramList = parseConstructor($reflction);
$obj = $reflction->newInstanceArgs($paramList);
return $obj;
}
/**
* 解析类的构造函数,返回参数列表
* @param ReflectionClass $reflction
* @return array
*/
function parseConstructor(ReflectionClass $reflction): array
{
$paramList = [];
// 如果构造方法存在,返回 object(ReflectionMethod) 反之返回 null
$constructor = $reflction->getConstructor();
if (!is_null($constructor)) {
// 返回数组 object(ReflectionParameter) 参数列表
$params = $constructor->getParameters();
foreach ($params as $param) {
// 获取参数的类型提示类,类型为 object(ReflectionClass) 若没有返回 null
if (!is_null($param->getClass())) {
// 获取类名
$paramList[] = createObj($param->getClass()->getName());
} else {
// 获取默认值
$paramList[] = $param->getDefaultValue();
}
}
}
return $paramList;
}
/**
* 解析返回类的某方法参数
*
* @param string $className
* @param string $methodName
* @return array
* @throws ReflectionException
*/
function parseMethod(string $className, string $methodName)
{
$paramList = [];
// object(ReflectionMethod)
$reflection = new ReflectionMethod($className, $methodName);
$params = $reflection->getParameters();
foreach ($params as $param) {
// 获取参数的类型提示类,类型为 object(ReflectionClass) 若没有返回 null
if (!is_null($param->getClass())) {
// 获取类名
$paramList[] = createObj($param->getClass()->getName());
} else {
// 获取默认值
$paramList[] = $param->getDefaultValue();
}
}
return $paramList;
}
function autoLoad($className)
{
require_once __DIR__.'/'.$className.'.php';
}
function dump($data)
{
echo '<pre>';
var_dump($data);
exit();
}
class TestA
<?php namespace a; use b\TestB;
use face\Test; class TestA implements Test
{
const VERSION = 'A';
public $name;
public $objB; public function __construct(TestB $b, $name='aaa')
{
$this->objB = $b;
$this->name = $name;
} public function hello(TestB $b)
{
var_dump($b);
}
}
class TestB
<?php namespace b; use face\Test;
use c\TestC; class TestB implements Test
{
const VERSION = 'B';
public $name;
public $objC; public function __construct($name = 'bbb', TestC $c)
{
$this->objC = $c;
$this->name = $name;
}
}
class TestC
<?php namespace c; use face\Test; class TestC implements Test
{
const VERSION = 'C'; public function __construct($name = 'ccc')
{
}
}
class Face
<?php namespace face; interface Test
{ }
另一个实例:
<?php class Point
{
public $x;
public $y; public function __construct($x = 0, $y = 0)
{
$this->x = $x;
$this->y = $y;
}
} class Circle
{
protected $radius; protected $center; public function __construct(Point $point, $raduis = 1)
{
$this->center = $point;
$this->radius = $raduis;
} public function printCenter()
{
printf('center coordinate is (%d, %d)', $this->center->x, $this->center->y);
} public function area()
{
return 3.14 * pow($this->radius, 2);
}
} class DI
{
public function make($className)
{
if (class_exists($className)) {
$reflectionClass = new ReflectionClass($className);
$constructor = $reflectionClass->getConstructor();
if (is_null($constructor)) {
return $reflectionClass->newInstance();
} else {
$parameters = $constructor->getParameters();
$dependencies = $this->getDependencies($parameters); return $reflectionClass->newInstanceArgs($dependencies);
} } else {
printf('%s', 'class is not exist');
}
} // 依赖解析
protected function getDependencies($parameters)
{
$dependencies = [];
foreach ($parameters as $parameter) {
$dependency = $parameter->getClass();
if (is_null($dependency)) {
if ($parameter->isDefaultValueAvailable()) {
$dependencies[] = $parameter->getDefaultValue();
} else {
//不是可选参数的为了简单直接赋值为字符串0
//针对构造方法的必须参数这个情况
//laravel是通过service provider注册closure到IocContainer,
//在closure里可以通过return new Class($param1, $param2)来返回类的实例
//然后在make时回调这个closure即可解析出对象
//具体细节我会在另一篇文章里面描述
$dependencies[] = '0';
}
} else {
//递归解析出依赖类的对象
$dependencies[] = $this->make($parameter->getClass()->name);
}
} return $dependencies;
}
} echo '<pre>';
$obj = (new DI)->make(Circle::class);
$obj->printCenter();
参考文档:
https://juejin.im/post/5cac58ecf265da03a85a9f9a#heading-0
https://juejin.im/post/5ae292e7518825673446c1fe
https://www.insp.top/learn-laravel-container
https://github.com/kevinyan815/Learning_Laravel_Kernel/blob/master/articles/reflection.md
依赖注入demo的更多相关文章
- 该项目的建设maven片:4.协调和依赖,spring依赖注入demo
源码下载 协调 <groupId>com.demo.animal</groupId> <artifactId>animal-core</artifactId& ...
- PHP 通过构造器进行依赖注入 demo
class A{ public $b; public $f; function __construct( B $b , $f = 1 ){ $this->b = $b; $this->f ...
- 【Java】 Spring依赖注入小试牛刀:编写第一个Spring ApplicationContext Demo
0 Spring的依赖注入大致是这样工作的: 将对象如何构造(ID是什么?是什么类型?给属性设置什么值?给构造函数传入什么值?)写入外部XML文件里.在调用者需要调用某个类时,不自行构造该类的对象, ...
- Spring之IOC/DI(反转控制/依赖注入)_入门Demo
在平时的java应用开发中,我们要实现某一个功能或者说是完成某个业务逻辑时至少需要两个或以上的对象来协作完成,在没有使用Spring的时候,每个对象在需要使用他的合作对象时,自己均要使用像new ob ...
- angular2系列教程(八)In-memory web api、HTTP服务、依赖注入、Observable
大家好,今天我们要讲是angular2的http功能模块,这个功能模块的代码不在angular2里面,需要我们另外引入: index.html <script src="lib/htt ...
- angularjs 依赖注入--自己学着实现
在用angular依赖注入时,感觉很好用,他的出现是 为了"削减计算机程序的耦合问题" ,我怀着敬畏与好奇的心情,轻轻的走进了angular源码,看看他到底是怎么实现的,我也想写个 ...
- 查看.NET Core源代码通过Autofac实现依赖注入到Controller属性
一.前言 在之前的文章[ASP.NET Core 整合Autofac和Castle实现自动AOP拦截]中,我们讲过除了ASP.NETCore自带的IOC容器外,如何使用Autofac来接管IServi ...
- C# 依赖注入
http://www.cnblogs.com/leoo2sk/archive/2009/06/17/1504693.html 这篇文章真的非常非常好···绝对值得收藏学习. 目录 目录 1 ...
- 采用dom4j和反射模拟Spring框架的依赖注入功能
Spring的依赖注入是指将对象的创建权交给Spring框架,将对象所依赖的属性注入进来的行为.在学习了dom4j后,其实也可以利用dom4j和反射做一个小Demo模拟Spring框架的这种功能.下面 ...
随机推荐
- STL库学习笔记(待补充QAQ
几百年前就说要学STL了然后现在还没动呢QAQ总算还是克服了懒癌决定学下QAQ 首先港下有哪几个vector listset map stack queue,大概就这些? 然后因为有几个基本操作每个都 ...
- php 与mysql 数据库
新手上路,php刚学,数据库刚学,花了两天终于读到数据库的数据了. 一路上的坎坷我在这里吐槽吐槽: <?php $mysql_server_name='localhost'; //改成自己的my ...
- 深入理解Spring AOP之二代理对象生成
深入理解Spring AOP之二代理对象生成 spring代理对象 上一篇博客中讲到了Spring的一些基本概念和初步讲了实现方法,当中提到了动态代理技术,包含JDK动态代理技术和Cglib动态代理 ...
- python练习题-day16
1.用map来处理字符串列表,把列表中所有人都变成sb,比方alex_sb name=["alex","wupeiqi","yuanhao" ...
- Navicat 远程连接 Oracle11g 数据库报错 No listener 的问题
1.首先确认已经启动 OracleOraDb11g_home1TNSListener 服务时,仍无法连接: 2.进入计算机系统属性中查看 Oracle 服务端计算机的全名: 3.进入 Orac ...
- Python3学习之路~5.10 PyYAML模块
Python也可以很容易的处理ymal文档格式,只不过需要安装一个模块,参考文档:http://pyyaml.org/wiki/PyYAMLDocumentation
- python-浅拷贝和深拷贝
浅拷贝和深拷贝 浅拷贝 拷贝的副本共享内部对象的引用的拷贝为浅拷贝 举个栗子 list1 = [1, 2, [3, 4], (5, 6)] list2= list(list1) print(" ...
- python基础(十三) cmd命令调用
python cmd命令调用 关于python调用cmd命令: 主要介绍两种方式: 1.python的OS模块. OS模块调用CMD命令有两种方式:os.popen(),os.system(). 都是 ...
- How do you explain Machine Learning and Data Mining to non Computer Science people?
How do you explain Machine Learning and Data Mining to non Computer Science people? Pararth Shah, ...
- C# Newtonsoft.Json JsonSerializerSettings 全局序列化设置
Newtonsoft.Json.JsonSerializerSettings setting = new Newtonsoft.Json.JsonSerializerSettings(); JsonC ...