直接上代码吧:
<?php
namespace App;
class Container
{
/**
* 容器绑定,用来装提供的实例或者 提供实例的回调函数
* @var array
*/
public $building = [];
/**
* 注册一个绑定到容器
*/
public function bind($abstract, $concrete = null, $shared = false)
{
if (is_null($concrete)) {
$concrete = $abstract;
}
if ($concrete instanceof Closure) {
$concrete = $this->getClosure($abstract, $concrete);
}
$this->building[$abstract] = compact("concrete", "shared");
}
//注册一个共享的绑定 单例
public function singleton($abstract, $concrete, $shared = true)
{
$this->bind($abstract, $concrete, $shared);
}
/**
* 默认生成实例的回调闭包
*
* @param $abstract
* @param $concrete
* @return Closure
*/
public function getClosure($abstract, $concrete)
{
return function ($c) use ($abstract, $concrete) {
$method = ($abstract == $concrete) ? 'build' : 'make';
return $c->$method($concrete);
};
}
/**
* 生成实例
*/
public function make($abstract)
{
$concrete = $this->getConcrete($abstract);
if ($this->isBuildable($concrete, $abstract)) {
$object = $this->build($concrete);
} else {
$object = $this->make($concrete);
}
return $object;
}
/**
* 获取绑定的回调函数
*/
public function getConcrete($abstract)
{
if (!isset($this->building[$abstract])) {
return $abstract;
}
return $this->building[$abstract]['concrete'];
}
/**
* 判断 是否 可以创建服务实体
*/
public function isBuildable($concrete, $abstract)
{
return $concrete === $abstract || $concrete instanceof Closure;
}
/**
* 根据实例具体名称实例具体对象
*/
public function build($concrete)
{
if ($concrete instanceof Closure) {
return $concrete($this);
}
//创建反射对象
$reflector = new \ReflectionClass($concrete);
if (!$reflector->isInstantiable()) {
//抛出异常
throw new \Exception('无法实例化');
}
$constructor = $reflector->getConstructor();
if (is_null($constructor)) {
return new $concrete;
}
$dependencies = $constructor->getParameters();
$instance = $this->getDependencies($dependencies);
return $reflector->newInstanceArgs($instance);
}
//通过反射解决参数依赖
public function getDependencies(array $dependencies)
{
$results = [];
foreach ($dependencies as $dependency) {
$results[] = is_null($dependency->getClass())
? $this->resolvedNonClass($dependency)
: $this->resolvedClass($dependency);
}
return $results;
}
//解决一个没有类型提示依赖
public function resolvedNonClass(ReflectionParameter $parameter)
{
if ($parameter->isDefaultValueAvailable()) {
return $parameter->getDefaultValue();
}
throw new \Exception('出错');
}
//通过容器解决依赖
public function resolvedClass(ReflectionParameter $parameter)
{
return $this->make($parameter->getClass()->name);
}
}
class Dog
{
public function dogCall()
{
return '汪汪汪';
}
}
class People
{
public $dog = null;
public function __construct()
{
$this->dog = new Dog();
}
public function putDog()
{
return $this->dog->dogCall();
}
}
//实例化容器类
$app = new Container();
//向容器中填充Dog
$app->bind('Dog', 'App\Dog');
//填充People
$app->bind('People', 'App\People');
//通过容器实现依赖注入,完成类的实例化;
$people = $app->make('People');
//调用方法
echo $people->putDog();
上面示例中我们先实例化容器类,然后使用bind()方法 绑定接口和 生成相应的实例的闭包函数。然后使用make() 函数生成实例对象,在make()中会调用 isBuildable($concrete, $abstract) 来判断 给定的服务实体($concrete参数)是否可以创建,可以创建 就会调用 build($concrete) 函数 ,build($concrete) 函数会判断传的参数是 是 闭包 还是 具体类名 ,如果是闭包则直接运行,如果是具体类名的话,则通过反射获取该类的构造函数所需的依赖,完成实例化。
来源:https://laravel-china.org/articles/4977/laravel-service-container-implementation-principle#reply15
搜索
标签
study
ab
amap
apache
apahe
awk
aws
bat
centos
CFS
chrome
cmd
cnpm
composer
consul
crontab
css
curl
cygwin
devops
di
docker
docker,docker-compose
ethereum
excel
fiddler
fluentd
framework
front-end
git
gitgui
github
glide
go
golang
gorm
grafana
gzip
ioc
item2
iterm2
javascript
jenkins
jsonp
kafka
laradock
laravel
larval
linux
liunux
log
mac
mac, wi-fi
macos
magento
mariaDB
minikube
mongoDB
msp
mysql
netbeans
nginx
nodejs
nohup
npm
nsq
php
php-fpm
php7
phpstorm
php扩展
Protobuf
python
redis
scp
server
shell
soap
socket
socket5
sql
sre
ssdb
ssh
ssl
study
sublime
swift
system
td-agent
uml
v2ray
vagrant
vagrnat
vim
vpn
vue
vue.js
webpack
webrtc
websocket
webtatic
windows
windows7
word
wps
xdebug
yarn
yii2
yum
zookeeper
世界国家
互联网
以太坊
分类
前端
小程序
打印机
排序算法
搞笑
权限
粤语
缓存
网络
虚拟机
视频
设计模式
项目管理
热门文章
友情链接