fredshare / blog

护卫银河
https://fredshare.github.com/blog/
112 stars 23 forks source link

phalapi-进阶篇2(DI依赖注入和单例模式) #34

Closed zhubobin closed 7 years ago

zhubobin commented 7 years ago

前言

先在这里感谢phalapi框架创始人@dogstar,为我们提供了这样一个优秀的开源框架.

离上一次更新过去了快两周,在其中编写了一个关于DB分表分库解决大数据量的拓展,有兴趣的童鞋可以了解了解.废话不多说,本小节在于解释一下在PhalApi框架中两个比较好的思想,单例模式和依赖注入.

  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;

}

其实不难我们只用吧new一个类的操作封装到我们需要new的类的静态方法在向上面一样的去判断,就可以很简单的去实现单例模式.

  1. 依赖注入

依赖注入又称之为"控制反转",如果是熟悉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会存到数组需要的时候会拿出来呢,感兴趣的童鞋可以百度一下魔法方法ser和get

/**大家可以看到这是PhalApi_DI中的魔法方法__set

public function __get($name){ return $this->get($name, NULL); }

看完之后大家是不是觉得很简单啊,大家以后也可以在自己设计类的时候采用这种灵活的魔法方法实现. 2.2 惰性加载

在PhalApi中的DI()方法也提供惰性加载,惰性加载如字意也就是当类没有被使用到的时候不会加载,这样的操作也是为了避免浪费不必要的资源,当我们不是用的时候永远不会去实例化只有当你使用到的时候才会去new这个类然后实例化之后使用,我们来看看是如何实现的.

//当我们执行以下语句的时候,在依赖注入的时候存的是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; }

作者: PhalApi 链接:http://www.imooc.com/article/6113 来源:慕课网