Hello,我是Rocket
这是我参与更文挑战的第3天,活动详情查看:更文挑战
- 要说laravel框架最核心的那肯定要属Ioc容器了
- 听着名字很高大上,你对它了解多少呢
- 什么是依赖注入
- Laravel bind、singleton 、instance 有什么区别呢
- 服务解析是怎么处理的
- 构建一个简单的容器加深大家对IOC容器的理解
1、普通new对象
<?php
//阿里云短信
class AliyunSms {
public function __construct(){}
public function send()
{
echo 'sms gateway by aliyun';
}
}
//百度云短信
class BaiduSms {
public function __construct(){}
public function send()
{
echo 'send gateway by baidu';
}
}
//发短信
class SMS {
private $sms;
public function __construct()
{
$this->sms= new AliyunSms ();
}
public function send()
{
$this->sms->send();
}
}
$pb = new SMS ();
$pb->send();
2、 依赖注入
<?php
//定义短信类接口
interface Smsinferface{
public function send();
}
//阿里云短信
class AliyunSms implements Smsinferface{
public function __construct(){}
public function send()
{
echo 'sms gateway by aliyun';
}
}
//百度云短信
class BaiduSms implements Smsinferface{
public function __construct(){}
public function send()
{
echo 'send gateway by baidu';
}
}
//发短信
class SMS {
private $sms;
public function __construct(Smsinferface $sms)
{
$this->sms= $sms;
}
public function send()
{
$this->sms->send();
}
}
//生成依赖
$aliyun = new AliyunSms();
//注入依赖
$a = new SMS ($aliyun);
$a->send();
$b = new SMS(new BaiduSms());
$b->send();
3、Laravel几个绑定实例的方法的区别
public function bind($abstract, $concrete = null, $shared = false)
public function singleton($abstract, $concrete = null)
{
$this->bind($abstract, $concrete, true);
}
public function instance($abstract, $instance)
4、解析服务的几种方式
$abstract = $this->getAlias($abstract);
$needsContextualBuild = ! empty($parameters) || ! is_null(
$this->getContextualConcrete($abstract)
);
if (isset($this->instances[$abstract]) && ! $needsContextualBuild) {
return $this->instances[$abstract];
}
$this->with[] = $parameters;
$concrete = $this->getConcrete($abstract);
if ($this->isBuildable($concrete, $abstract)) {
$object = $this->build($concrete);
} else {
$object = $this->make($concrete);
}
foreach ($this->getExtenders($abstract) as $extender) {
$object = $extender($object, $this);
}
if ($this->isShared($abstract) && ! $needsContextualBuild) {
$this->instances[$abstract] = $object;
}
$this->fireResolvingCallbacks($abstract, $object);
$this->resolved[$abstract] = true;
array_pop($this->with);
return $object;
if (! function_exists('resolve')) {
function resolve($name)
{
return app($name);
}
}
function app($abstract = null, array $parameters = [])
{
if (is_null($abstract)) {
return Container::getInstance();
}
return Container::getInstance()->make($abstract, $parameters);
}
5、构建一个简单的容器类
实现IOC容器的基本功能,绑定、解析、依赖倒置以及控制翻转
class Container
{
// 保存与接口绑定的闭包,
// 闭包必须能够返回接口的实例。
protected $bindings = [];
//单例实例
protected $instances = [];
// 为某个接口绑定一个实现,有两种情况:
//
// 第一种是绑定接口的实现的类名;
// 第二种是绑定一个闭包,这个闭包应该返回接口的实例。
//
// 不管哪种情况,实例化操作都是调用 build() 方法完成。
//
// 第二种情况,主要是为了能够在实例化前后进行额外的操作,
// 实例化的逻辑就书写在闭包中。
public function bind($abstract, $concrete = null,$shared= false)
{
if (is_null($concrete)) {
$concrete = $abstract;
}
// 如果提供的参数不是闭包,而是一个类,
// 则构建一个闭包,直接调用 build() 方法进行实例化
if (!$concrete instanceof Closure) {
// 调用闭包时,传入的参数是容器本身,即 $this生成默认的
$concrete = function ($c) use ($concrete) {
return $c->build($concrete);
};
}
$this->bindings[$abstract] = compact('concrete','shared');
}
//单例绑定
public function singleton($abstract, $concrete = null)
{
$this->bind($abstract, $concrete, true);
}
//获取对应的闭包
public function getConcrete($abstract){
if (isset($this->bindings[$abstract])) {
return $this->bindings[$abstract]['concrete'];
}
return $abstract;
}
public function isShared($abstract)
{
return isset($this->instances[$abstract]) ||
(isset($this->bindings[$abstract]['shared']) &&
$this->bindings[$abstract]['shared'] === true);
}
// 生成指定接口的实例
public function make($abstract)
{
if (isset($this->instances[$abstract])) {
return $this->instances[$abstract];
}
// 取出闭包
$concrete = $this->getConcrete($abstract);
// 取得实例
$object = $this->build($concrete);
// 判断是否需要分享对象(单例)
if ($this->isShared($abstract)) {
$this->instances[$abstract] = $object;
}
return $object;
}
// 生成实例
public function build($concrete)
{
//如果是闭包直接调用闭包函数
if ($concrete instanceof Closure) {
return $concrete($this);
}
// 取得类的反射
$reflector = new ReflectionClass($concrete);
// 检查类是否可实例化
if (! $reflector->isInstantiable()) {
// 如果不能,意味着接口不能正常工作,报错
echo "Target [$concrete] is not instantiable";
}
// 取得构造函数的反射
$constructor = $reflector->getConstructor();
// 检查是否有构造函数
if (is_null($constructor)) {
// 如果没有,就说明没有依赖,直接实例化
return new $concrete;
}
// 取得包含每个参数的反射的数组
$parameters = $constructor->getParameters();
// 返回一个真正的参数列表,那些被类型提示的参数已经被注入相应的实例
$realParameters = $this->resolveDependencies($parameters);
return $reflector->newInstanceArgs($realParameters);
}
//解析参数依赖
protected function resolveDependencies($parameters)
{
$realParameters = [];
foreach($parameters as $parameter) {
// 如果一个参数被类型提示为类 foo,
// 则这个方法将返回类 foo 的反射
$dependency = $parameter->getClass();
if(is_null($dependency)) {
$realParameters[] = NULL;
} else {
$realParameters[] = $this->make($dependency->name);
}
}
return (array)$realParameters;
}
}
$app = new Container();
$app->bind(Smsinferface::class, BaiduSms::class);
$app->bind('sms', SMS::class);//可以理解成别名
$sms = $app->make('sms');
$sms->send();
//单例绑定
$app->singleton('newsms', SMS::class);
$newsms = $app->make('newsms');
$newsms2 = $app->make('newsms');
var_dump($sms === $newsms);
var_dump($newsms === $newsms2);
6、结尾
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!