💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
#phalapi-进阶篇2(DI依赖注入和单例模式)# ![](http://webtools.qiniudn.com/master-LOGO-20150410_50.jpg) ##前言## ***先在这里感谢phalapi框架创始人@dogstar,为我们提供了这样一个优秀的开源框架.*** 离上一次更新过去了快两周,在其中编写了一个关于DB分表分库解决大数据量的拓展,有兴趣的童鞋可以了解了解.废话不多说,本小节在于解释一下在PhalApi框架中两个比较好的思想,单例模式和依赖注入. 附上: 喵了个咪的博客:[w-blog.cn](w-blog.cn) 官网地址:[http://www.phalapi.net/](http://www.phalapi.net/ "PhalApi官网") 开源中国Git地址:[http://git.oschina.net/dogstar/PhalApi/tree/release](http://git.oschina.net/dogstar/PhalApi/tree/release "开源中国Git地址") ##1. 单例模式## 单例模式对于长期进行过面向对象编程的童鞋应该不算陌生,对学习php的童鞋也应该有听过,这里简单的聊一聊单例模式它到底是一个怎么样的东东,解决了怎么样的问题,并且在PhalApi中它是如何实现的. 单例单例,所谓单例也就是保证一个类仅有一个实例,并提供一个访问它的全局访问点,这就是单例,不难看出他的好处:资源利用少,因为只有一个,大家都是知道要使用一个类必须要实例他,也就是new,在每次new一个对象的时候都会在内存中生成一块区域来存放这个实例,如果在程序一次运行中使用了很多的new实例化了同一个对象,那就比较消耗资源了,但是如果是通用一个使用全局变量**global**程序又会显得不那么优雅而且会很乱,在这种情况下,单例模式就产生了. 单例模式是一个很好的解决方案,既可以全局通用,又不必担心占用过多的资源,且非常优雅。我们来一起看看在PhalApi中是如何实现单例模式的: //大家看到我们常用的DI方法内部实现的是PhalApi_DI中的静态方法one方法 function DI() { return PhalApi_DI::one(); } 然后我们看向one方法内部 每当请求过来时先验证静态变量instance是否已被类初始化赋值,若无,则会在内部去实例化**PhalApi_DI**类,然后赋值给**$instance**并返回,若有,则当下次请求过来时,直接返回已实例化的对象。简言之,PhalApi框架所有的地方使用的DI方法,其实都是返回同一个对象实例,在内存中只存在一块区域,代码如下: public static function one(){ if(self::$instance == NULL){ self::$instance = new PhalApi_DI(); self::$instance->onConstruct(); } return self::$instance; } ##2. 依赖注入## 依赖注入又称之为**"控制反转"**,如果是熟悉javaweb开发的**spring**框架应该有比较深的感触,在这里也不往深的讲,就简单讲解一下PhalApi中DI依赖注入的实现,以便让大家了解这种设计模式实现原理以及自此基础上实现的惰性加载机制. ###2.1 DI依赖注入实现### 大家在PhalApi中常用的**DI()**方法,也就是采用我们上面所谓的单例模式,我们每次使用DI()就是在使用**PhalApi_DI**类,其实我们依赖注入的关键也就是在PhalApi_DI之中 先来讲一下他的一个实现方式再来讲具体实现,这里举个例子: //配置 DI()->config = new PhalApi_Config_File(API_ROOT . '/Config'); 其实在内部有一个数组,它把**config**作为了key,把**new PhalApi_Config_File(API_ROOT . '/Config')**作为了value,然后保存了起来。当我们下一次使用**DI->config->get()**的时候,它就会根据key值config拿出开始new好的类,所以可以说**config操作是依赖于DI()**,而且在使用DI()->config的时候永远都是在使用同一个实例,减少资源的消耗. 有的童鞋就好奇了为什么DI()->config会存到数组里而在需要的时候会拿出来?感兴趣的童鞋可以百度一下魔法方法**__set和__get** /**大家可以看到这是PhalApi_DI中的魔法方法__set * 也就是当使用DI()->config = new PhalApi_Config_File(API_ROOT . '/Config');的时候 * 获得的name值就是config,获得的value也就是new PhalApi_Config_File(API_ROOT . '/Config'); */get同理,在内部实现都是调用了内部get和set方法 public function __set($name, $value){ $this->set($name, $value); } public function __get($name){ return $this->get($name, NULL); } 看完之后大家是不是觉得很简单啊,大家以后也可以在设计自己的类的时候采用这种灵活的魔法方法实现. ###2.2 惰性加载### 在PhalApi中的DI()方法也提供惰性加载,惰性加载如字意也就是当类没有被使用到的时候不会被加载,这样的操作也是为了避免浪费不必要的资源,当我们不使用的时候永远不会去实例化,只有当你使用到的时候才会去实例化。接下来,我们来看看是如何实现的. //当我们执行以下语句的时候,在依赖注入的时候存的是value值是字符串的test DI()->test = 'test'; //使用DI()->test->test();的时候会使用到PhalApi中的get方法,在get方法中有一段代码 $this->data[$key] = $this->initService($this->data[$key]); //在initService方法内部验证了value是字符串就实例化了再返回 if($config instanceOf Closure){ $rs = $config(); }elseif(is_string($config) && class_exists($config)){ $rs = new $config(); if(is_callable(array($rs, 'onInitialize'))){ call_user_func(array($rs, 'onInitialize')); } }else{ $rs = $config; } ##3. 总结## 在本节中简单的讲解了关于单例模式,依赖注入以及惰性加载,这几种设计模式都是常用的,能够减少资源利用率,希望大家看了这篇介绍能够亲自地去体验一下PhalApi中的这几种模式。在下一小节就讲解如何构建自己的拦截器,希望大家能够继续关注! 注:笔者能力有限,有说的不对的地方,希望大家能够指出,也希望多多交流! **官网QQ交流群:421032344 欢迎大家的加入!** ####[上一章](/wikis/%5b7.7%5d-phalapi-%e8%bf%9b%e9%98%b6%e7%af%871(%e4%b8%89%e5%b1%82%e7%bb%93%e6%9e%84Api%2cDomain%2c%e5%92%8cModel).html) [文档首页](/wikis/) [下一章](/wikis/%5b7.9%5d-phalapi-%e8%bf%9b%e9%98%b6%e7%af%873(%e8%87%aa%e5%8a%a8%e5%8a%a0%e8%bd%bd%e5%92%8c%e6%8b%a6%e6%88%aa%e5%99%a8).html)