laravel学习:php写一个简单的ioc服务管理容器
php写一个简单的ioc服务管理容器
最近学习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服务管理容器的更多相关文章
- 【Linux学习】 写一个简单的Makefile编译源码获取当前系统时间
打算学习一下Linux,这两天先看了一下gcc的简单用法以及makefile的写法,今天是周末,天气闷热超市,早晨突然发现住处的冰箱可以用了,于是先出去吃了点东西,然后去超市买了一坨冰棍,老冰棍居多, ...
- JS入门学习,写一个简单的选项卡
/* 经过昨天一整天的纠结和摸索.总结下学习初期我最致命的几个问题…… 1.var oDiv = document.getElementById(''); 一定要多输,熟悉后o u什么的字母别搞 ...
- JS入门学习,写一个简单的图片库
<!-- 新手刚开始学JS,每天坚持写点东西 坚持下去,希望能有所进步 . 加油~~ --> <!DOCTYPE html> ...
- 【jQuery学习】写一个简单的弹框页面,火狐浏览器有弹框,但IE8没有弹框的原因?
我也是刚学习jQuery,就从官网上下载了jQuery的包,版本是3.2.1 代码 如下: <!DOCTYPE html> <html> <head> <me ...
- socket手写一个简单的web服务端
直接进入正题吧,下面的代码都是我在pycharm中写好,再粘贴上来的 import socket server = socket.socket() server.bind(('127.0.0.1', ...
- linux设备驱动第三篇:如何写一个简单的字符设备驱动?
在linux设备驱动第一篇:设备驱动程序简介中简单介绍了字符驱动,本篇简单介绍如何写一个简单的字符设备驱动.本篇借鉴LDD中的源码,实现一个与硬件设备无关的字符设备驱动,仅仅操作从内核中分配的一些内存 ...
- linux设备驱动第三篇:写一个简单的字符设备驱动
在linux设备驱动第一篇:设备驱动程序简介中简单介绍了字符驱动,本篇简单介绍如何写一个简单的字符设备驱动.本篇借鉴LDD中的源码,实现一个与硬件设备无关的字符设备驱动,仅仅操作从内核中分 ...
- (原创)如何使用boost.asio写一个简单的通信程序(一)
boost.asio相信很多人听说过,作为一个跨平台的通信库,它的性能是很出色的,然而它却谈不上好用,里面有很多地方稍不注意就会出错,要正确的用好asio还是需要花一番精力去学习和实践的,本文将通过介 ...
- [pixhawk笔记]4-如何写一个简单的应用程序
本文主要内容来自于:https://dev.px4.io/en/tutorials/tutorial_hello_sky.html,并对文档中的部分问题进行更正. 本文假设已经建立好开发环境并能正确编 ...
随机推荐
- 并不对劲的bzoj3998:loj2102:p3975:[TJOI2015]弦论
题目大意 对于一个给定的长度为n(\(n\leq5*10^5\))的字符串, 分别求出不同位置的相同子串算作一个.不同位置的相同子串算作多个时,它的第k(\(k\leq10^9\))小子串是什么 题解 ...
- java数组与字符串相互转换、整型与字符串相互转换【详解】
java 数组->字符串 1.char数组(字符数组)->字符串 可以通过:使用String.copyValueOf(charArray)函数实现. 举例: char[] arr={ ...
- echarts 实例demo 详细讲解
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> & ...
- 【SpringCloud构建微服务系列】学习断路器Hystrix
一.Hystrix简介 在微服务架构中经常包括多个服务层,比如A为B提供服务,B为C和D提供服务,如果A出故障了就会导致B也不可用,最终导致C和D也不可用,这就形成了雪崩效应. 所以为了应对这种情况, ...
- 【css】rem及其替换方案
移动端的web前端开发其实经常会有一些令人头疼的问题,比如屏幕适配.1像素问题等,rem也是之前在屏幕适配上比较完善的一套方案,但是随着业务的深入,任何方案都有其优秀与不足的地方,rem这套方案也一样 ...
- 数学 SCU 4436 Easy Math
题目传送门 /* 数学题:当有一个数开根号后是无理数,则No */ #include <cstdio> #include <algorithm> #include <cs ...
- 题解报告:hdu 1421 搬寝室(递推dp)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1421 Problem Description 搬寝室是很累的,xhd深有体会.时间追述2006年7月9 ...
- 1475 建设国家 DP
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1475 这题转化过来就是,给定n个点,每个点都有一个过期时间,一个价值.现 ...
- 转】用Nodejs连接MySQL
原博文出自于: http://blog.fens.me/category/%E6%95%B0%E6%8D%AE%E5%BA%93/page/2/ 感谢! 用Nodejs连接MySQL 从零开始node ...
- Quartz~关于cron表达式要说的
每20秒执行一次