php写一个简单的ioc服务管理容器

原创: 陈晨 CoderStory 2018-01-14

最近学习laravel框架,了解到laravel核心是一个大容器,这个容器负责几乎所有服务组件的实例化以及实例的生命周期管理。这种方式能够很好地对代码进行解耦,使得应用程序的业务代码不必操心服务组件的对象从何而来,当需要一个服务类来完成某个功能的时候,仅需要通过容器解析出该类型的一个实例即可。

最近很焦虑,感觉自己的竞争力越来越弱(现阶段已完全成为一个IT搬砖工),道理大家都懂,但是想要摆脱搬砖工,走向砌墙工需要技术的慢慢积累,千里之行始于足下,那么这个周末就先写一个简单的ioc容器吧 哈哈。。。。

参考了laravel容器的源码,简单分析一番,ioc容器只需实现两个功能,

一、 注册服务(bind)

一般都是在程序刚加载的时候进行服务的注册,只是注册,不进行实例化,在真正用到的时候再进行实例化,这样做减少了资源浪费,做到了按需分配资源。

有些特殊类是单例模式,再注册的时候进行区分

二、实例化服务(make)

从已注册服务的列表中选取要实例化的服务,返回实例对象

=====================================

Container.class.php 代码如下

=====================================

<?php

class Container implements ArrayAccess

{

//注册服务列表

private $_bindings = array();

//实例服务列表

private $_instances = array();

//注册普通服务

public function set($name,$class)

{

$this->bind($name,$class);

}

//注册单例服务

public function setShared($name,$class)

{

$this->bind($name,$class,true);

}

//注册服务

private function bind($name,$class,$shared=false)

{

//卸载服务

$this->remove($name);

//如果是对象直接放入实例服务列表

if(!($class instanceof Closure) && is_object($class))

{

$this->_instances[$name] = $class;

}else{

$this->_bindings[$name]  = array('class' => $class,'shared'=>$shared);

}

}

//获取服务

public function make($name,$params=array()){

//判断服务是否实例化

if (isset($this->_instances[$name])) {

return $this->_instances[$name];

}

//检测是否注册服务

if (!isset($this->_bindings[$name])) {

return null;

}

$concrete = $this->_bindings[$name]['class'];

$obj = null;

//闭包形式注册

if ($concrete instanceof Closure) {

$obj = call_user_func_array($concrete, $params);//通过回调函数调用这个函数

}elseif (is_string($concrete)) {//字符串方式

if (empty($params)) {

$obj= new $concrete;

}else{//直接传入实例对象

//带参数的类的实例化

// $class = new ReflectionClass($concrete);

// $obj = $class->newInstanceArgs($params);

$obj = $concrete;

}

}

//如果是单例模式,则写入_instances列表

if ($this->_bindings[$name]['shared'] == true && $obj) {

$this->_instances[$name] = $obj;

}

return $obj;

}

//检测服务是否存在

public function has($name)

{

return isset($this->_bindings[$name]) or isset($this->_instances[$name]);

}

//卸载服务

public function remove($name)

{

unset($this->_bindings[$name],$this->_instances[$name]);

}

//ArrayAccess接口,检测服务是否存在

public function offsetExists($offset) {

return $this->has($offset);

}

//ArrayAccess接口,以$di[$name]方式获取服务

public function offsetGet($offset) {

return $this->get($offset);

}

//ArrayAccess接口,以$di[$name]=$value方式注册服务,非共享

public function offsetSet($offset, $value) {

return $this->set($offset,$value);

}

//ArrayAccess接口,以unset($di[$name])方式卸载服务

public function offsetUnset($offset) {

return $this->remove($offset);

}

}

?>

=========================================

index.php 测试代码

先声明一个汽车接口类Car,接口有个paiLiang方法

不同品牌的汽车实现Car接口 (假设一个品牌汽车就一种排量)

实现了通过IOC容器管理类的注册和实例化以及依赖注入(通过注入不同的Car实现类,制造不同排量的汽车)

=========================================

<?php

header("Content-Type:text/html;charset=utf8");

include("Container.class.php");

interface Car

{

//排量

public function paiLiang();

}

class Audi implements Car

{

public function paiLiang()

{

return "我是奥迪,排量3.0L";

}

}

class Bmw implements Car

{

public function paiLiang()

{

return "我是宝马,排量2.0T";

}

}

class CarFactory

{

public $paiLiang;

public function __construct(Car $car)

{

$this->paiLiang = $car->paiLiang();

}

}

//实例化容器

$app = new Container();

//注册奥迪和宝马服务

$app->set('audi','Audi');

$app->set('bmw','Bmw');

//注册汽车生产服务

$app->set('carFactory','CarFactory');

//echo $audi->paiLiang();

//获取要生产奥迪车的排量

$newCar = $app->make('carFactory',array($app->make('audi')));

print_r($newCar->paiLiang.'<br>');

$newCar = $app->make('carFactory',array($app->make('bmw')));

print_r($newCar->paiLiang);

输出结果:

我是奥迪,排量3.0L
我是宝马,排量2.0T

laravel学习:php写一个简单的ioc服务管理容器的更多相关文章

  1. 【Linux学习】 写一个简单的Makefile编译源码获取当前系统时间

    打算学习一下Linux,这两天先看了一下gcc的简单用法以及makefile的写法,今天是周末,天气闷热超市,早晨突然发现住处的冰箱可以用了,于是先出去吃了点东西,然后去超市买了一坨冰棍,老冰棍居多, ...

  2. JS入门学习,写一个简单的选项卡

    /* 经过昨天一整天的纠结和摸索.总结下学习初期我最致命的几个问题…… 1.var oDiv = document.getElementById('');    一定要多输,熟悉后o u什么的字母别搞 ...

  3. JS入门学习,写一个简单的图片库

    <!-- 新手刚开始学JS,每天坚持写点东西 坚持下去,希望能有所进步 .  加油~~ --> <!DOCTYPE html>                         ...

  4. 【jQuery学习】写一个简单的弹框页面,火狐浏览器有弹框,但IE8没有弹框的原因?

    我也是刚学习jQuery,就从官网上下载了jQuery的包,版本是3.2.1 代码 如下: <!DOCTYPE html> <html> <head> <me ...

  5. socket手写一个简单的web服务端

    直接进入正题吧,下面的代码都是我在pycharm中写好,再粘贴上来的 import socket server = socket.socket() server.bind(('127.0.0.1', ...

  6. linux设备驱动第三篇:如何写一个简单的字符设备驱动?

    在linux设备驱动第一篇:设备驱动程序简介中简单介绍了字符驱动,本篇简单介绍如何写一个简单的字符设备驱动.本篇借鉴LDD中的源码,实现一个与硬件设备无关的字符设备驱动,仅仅操作从内核中分配的一些内存 ...

  7. linux设备驱动第三篇:写一个简单的字符设备驱动

          在linux设备驱动第一篇:设备驱动程序简介中简单介绍了字符驱动,本篇简单介绍如何写一个简单的字符设备驱动.本篇借鉴LDD中的源码,实现一个与硬件设备无关的字符设备驱动,仅仅操作从内核中分 ...

  8. (原创)如何使用boost.asio写一个简单的通信程序(一)

    boost.asio相信很多人听说过,作为一个跨平台的通信库,它的性能是很出色的,然而它却谈不上好用,里面有很多地方稍不注意就会出错,要正确的用好asio还是需要花一番精力去学习和实践的,本文将通过介 ...

  9. [pixhawk笔记]4-如何写一个简单的应用程序

    本文主要内容来自于:https://dev.px4.io/en/tutorials/tutorial_hello_sky.html,并对文档中的部分问题进行更正. 本文假设已经建立好开发环境并能正确编 ...

随机推荐

  1. bzoj 1941 Hide and Seek

    题目大意: n个点,求每个点到其最远点距离-到其最近点距离(除自己之外)的最小值 思路: 对于估计函数的理解还不够深刻 #include<iostream> #include<cst ...

  2. bzoj2693

    线性筛+莫比乌斯反演 盗波图 来自candy?大神 反演很重要的一条公式就是[gcd(i,j)==1]= 线性筛怎么推呢? 我们分4个步骤,1.先推出f[1],2.推出f[p],p是一个质数,3.由于 ...

  3. java笔记之线程简述1

    1:线程是依赖于进程而存在. 2:什么是进程?  通过任务管理器我们就看到了进程的存在.  而通过观察,我们发现只有运行的程序才会出现进程.  进程:就是正在运行的程序.  进程是系统进行资源分配和调 ...

  4. The Power of Android Action Bars(转载)

    转自:http://www.informit.com/articles/article.aspx?p=1743642

  5. Thinkpad x230i安装Ubuntu10.04发生no network devices available

    这个是由于10.04版本没有集成x230i的网卡驱动导致,需要到http://sourceforge.net/projects/e1000/f ... %20stable/下载最新版本驱动,并安装,之 ...

  6. bzoj P1979 华容道【bfs+spfa】

    调死我了-- 首先观察移动方式,需要移动的格子每次移动到相邻格子,一定是先把空白格子挪过去,所以我们得到一种做法,就是bfs预处理出每一个格子的四联通格子之间的空白格子移动距离建边,注意这个移动是不能 ...

  7. 421 Maximum XOR of Two Numbers in an Array 数组中两个数的最大异或值

    给定一个非空数组,数组中元素为 a0, a1, a2, … , an-1,其中 0 ≤ ai < 231 .找到 ai 和aj 最大的异或 (XOR) 运算结果,其中0 ≤ i,  j < ...

  8. DEV—【GridControl 按钮列无法触发点击事件解决方案】

    需要在按钮列的OptionColumn属性栏中找到下面两个属性,并且改为True AllowEdit=True,AllowFocus=True.

  9. android开发学习 ------- 弹出框

    这是一种方法,是我觉得简单易懂代码量较少的一种: /* 创建AlertDialog对象并显示 */ final AlertDialog alertDialog = new AlertDialog.Bu ...

  10. sql server添加用户和给用户授权

    --创建用户CREATE LOGIN 用户名 WITH PASSWORD=N'密码', DEFAULT_DATABASE=数据库名, CHECK_EXPIRATION=OFF, CHECK_POLIC ...