Zend Framework 2中如何使用Service Manager
end Framework 2 使用ServiceManager(简称SM)来实现控制反转(IoC)。有很多资料介绍了service managers的背景,我推荐大家看看this blog post from Evan和 this post from Reese Wilson,但是仍然有很多开发者不能够很好地使用ServiceManager去解决他们的需求。这篇文章我将解释为什么ZF2框架需要使用多个服务管理器以及怎样使用它们。主要包含以下几个方面:
- 这些不同的服务管理器是什么?
- 不同的服务管理器用来干什么?
- 服务管理器与服务定位器是什么关系?
- 如何使用这些服务管理器定义服务?
- 如何在一个服务管理器中通过另一个服务管理器调用服务?
服务管理器使用在ZF2的许多地方,其中最重要的四个地方是:
- 应用全局服务管理(根服务管理器或者说是主要服务管理器)
- 控制器
- 控制器插件
- 视图助手
每一组功能都有一个服务管理器,这样做的好处是,可以使用同一个服务Key值指向不同的服务。假如有一个名为url的试图助手,也有一个名为url的控制器插件,如果只有一个服务管理器的话很难使用一个url Key值达到这个目的,而使用多个服务管理器可以轻松做到。
还有一个原因是出于安全考虑。假设有一个route向controller传递一个参数,通过此参数,服务管理器可以实例化相应的服务,如果你没有考虑安全问题,那么可以通过给一个服务管理器提供各种各样的参数从而实例化所有服务。
服务管理器与服务定位器的不同
很多人问ServiceLocator和ServiceManager有什么不同。ServiceLocator(简称SL)是一个接口:
namespace Zend\ServiceManager; |
ServiceManager是ServiceLocator的一个具体实现。在zf2中SL的默认实现是SM。在整个框架中,有时会看到 getServiceLocator()方法,而有时会看到getServiceManager()方法。getServiceLocator()获得的 SL接口,而getServiceManager获得的是具体的SM实现。
两者之间并没有很大的区别,因为他们通常返回的是同一个对象。但是有时候一个SL可以有多个不同SM实现,许多zf2组件需要明确指定一个实现。
配置服务管理器
两种方法可以配置服务管理器:1.module类本身可以return SM配置; 2.模块配置文件(通常是config/module.config.php)可以return SM配置。两种方法功能是一样的,只是看你自己喜欢放置到哪儿。
你可以使用下面任意一种方法添加服务:
/** |
/** |
我们看到,两种不同的方法中返回的数组都是一样的,四种类型的服务管理器都是这样的。在module类中,你只需要实现getServiceConfig方法,配置就会被加载,使用的是duck type模式(不一定要继承,只要他们方法一样,就认为他们是一回事。例如:有一只鸟,如果它像鸭子一样叫,像鸭子一样游泳,像鸭子一样走路,就认为它就是一只鸭子)。如果你想严格规范这个方法,也可以添加一个接口。例如:
namespace MyModule; |
四种服务管理器,你都可以添加一个Key到模块配置文件或者添加一个方法到模块类。对于后者,你可以duck type一些方法也可以添加一个新的接口在Zend\MoudleManager\Feature\*interface。下面的列表反映了他们之间的联 系。“manager”代表管理什么,还提供了管理器类名、模块配置数组中的Key、模块的方法和接口。对于controller、controller plugin、view helper管理器,在全局管理器service manger中注册服务时指定了service name(服务名称)。
Manager: Application services
- Manager class: Zend\ServiceManager\ServiceManager
- Config key: service_manager
- Module method: getServiceConfig()
- Module interface: ServiceProviderInterface
Manager: Controllers
- Manager class: Zend\Mvc\Controller\ControllerManager
- Config key: controllers
- Module method: getControllerConfig()
- Module interface: ControllerProviderInterface
- Service name: ControllerLoader
Manager: Controller plugins
- Manager class: Zend\Mvc\Controller\PluginManager
- Config key: controller_plugins
- Module method: getControllerPluginConfig()
- Module interface: ControllerPluginProviderInterface
- Service name: ControllerPluginManager
Manager: View helpers
- Manager class: Zend\View\HelperPluginManager
- Config key: view_helpers
- Module method: getViewHelperConfig()
- Service name: ViewHelperManager
需要注意的是
有一关键点我们需要注意,正如Evan解释,对于一个工厂类有两个选项,要么是一个闭包,要么是一个字符串指向的类。这个类必须实现Zend\ServiceManager\FactoryInterface接口,或者它必须有__invoke方法。这个工厂将被放置到模块配置文件中,或者模块类中。
如果模块配置文件中使用闭包,就会有问题,因为所有的模块配置文件都将缓存到一个大的合并后的配置文件中,然而PHP中的闭包不能被序列化,不能被合并后缓存。所以你要么在模块配置文件中使用工厂类,要么使用getServiceConfig()方法。
根服务管理器与其他管理器的比较
根(root)通常在讨论IRC时使用,好像它是基础代码一样,但是实际上它与zf2的基础代码不是毫无关联。“根服务管理器”这个名字的也许来自
于:Zend\ServiceManager\ServiceManager控制着所有主要的服务,而其他的服务管理器只专注于一种服务。“根”这个名字
好像暗示着它与其他一些managers有着某种关系。猜一猜是不是这样呢?确实,有一种联系存在。
假设你有一个controller,需要注入一个cache(缓存实例)进去。controller在controller service
manager中具有缓存实例的工厂factory,缓存是root service
manager的一个service。在controller服务管理器的工厂中如何获得缓存服务?这就是root service
manager(根服务管理器)与其他服务管理器的关联之处。controller、controller plugin、view
helper的service
manager都是AbstractPluginMangaer抽象类的实现(Implementation),这个类有一个方法
getServiceLocator()能够返回root service manager,这使得各种不同的服务管理器能够来回调用:
/*在Module.config.php中*/ |
这里cache服务通过root service locator(根服务定位器)获得,通过$sm->getServiceLocator()可以获得任何根服务管理器下的服务。
如果你知道controller plugin manager和view helper manager 是注册在root service locator的话,这将变得非常有趣。你可以轻松的在一个服务中注入一个运行时对象到view helper中。例如,在url view helper(服务)中注入router(对象),这个对象对于使用route名字来组装url是必须的。
你可以通过“ControllerPluginManager”这个Key从根服务管理器(root SM)中获得controller plugin manager,view helper manager对应的Key是“ViewHelperManager”,你可以像这样获得一个插件:
use MyModule\Service; |
点对点的(peering) service manager
点对点service manager的概念很简单,就是说controller plugin和view helper service manager从root SM调用其他服务时不适用$sm->getServiveLocator()。点对点(peering)的主要意思是,controller plugin SM 加载自己的服务失败后再从root SM中加载服务。
因此,看上面的例子,在某种场合下,你可以跳过$sm->getServiceLocator(),直接获取服务。这只适用于 controller plugins和view helpers,对于controller SM是不适用的。原因很显然,controller SM有一个安全问题:你有可能由于请求了一个特俗的URL而意外地实例化了一个对象。如果你允许controller SM点对点获取服务的话,你将导致安全漏洞。尽管这样但是对于controller plugin和view helper,点对点仍然是有价值的。
use MyModule\Controller\Plugin; |
这么做的好处就是对于controller plugin和view helper,你可以忽略getServiceLocator(),这使得你的代码更加易读。在字里行间你可能读到了我的担忧:点对点并不是很容易掌握。 在上面的例子中,$sm并没有“my-cache”这个服务,但是你尝试去获取这个服务,你将得到cache。(这个地方不是很明白)。最好对这个工厂做 好文档,否则以后将会遇到麻烦。
个人喜好
我更加喜欢在Module中使用严格的接口。我总是使用Zend\ModuleManager\Feature interfaces,我总是把所有的service的配置放到一个config文件中,使用闭包作为工厂,这使得我可以清楚看到一个module中所有 的service key,而不是混杂着route config(从module config文件)或者 autoload config 或者 bootstrap 逻辑(从Module类)。
通常在module.config.php同目录旁边放置一个servcie.config.php文件在config/目录下面,然后include这个文件就像include module配置文件一样。Module类通常像这样:
namespace MyModule; |
module.config.php文件提供一些基础配置,service.config.php把所有的服务整合到一起。通过EnsembleKernel这个例子可以了解这种配置方式,其中service.config.php看起来像这样。当然,也有一些别的方法能够处理的非常好,看你个人喜好了。
英文原文链接 Using Zend Framework service managers in your application
本文是作者的团队博客ComingX上 Zend Framework 2中如何使用Service Manager 文章的一份拷贝,同为原创文章。
Zend Framework 2中如何使用Service Manager的更多相关文章
- zend framework安装中出现的问题与总结
1.按照官方的教程来做http://framework.zend.com/manual/current/en/user-guide/skeleton-application.html 但其中有些步骤没 ...
- 关于Zend Framework 2中 Zend\Session的使用
一直迷惑于zend\Session的使用,这个是Zend\Session的官方教程的中文版,http://zend-framework-2.yangfan.co/blog/556. 其中最重要的是关于 ...
- 在zend framework框架中try{}catch(Exception e){}的跳转问题
请勿盗版,转载请加上出处http://blog.csdn.net/yanlintao1 首先我先说明我遇到的问题 try{ //导入学生信息 $ModelStudent->insert($dat ...
- 【原创】Zend Framework 2框架之MVC
ZendFramework 2框架之MVC 作者:sys(360电商技术组) 1.前言 Zend Framework 2是zend官方推出的php开源框架,基于php5.3.他全然採用面向对象的代码实 ...
- 浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6627260 在前面一篇文章浅谈Service ...
- Zend Framework 1 - Quick Start
创建 Zend 项目 要创建 Zend 项目,首先要下载并解压 Zend Framework. 安装 Zend Framework 下载最新的 Zend Framework 1.12.20 源码包,( ...
- Ubuntu14.0下安装Zend Framework 2
Ubuntu14.0下安装Zend Framework 2为了安装这个东西,忙活了快一天了,参考中文博客一直没有安装成功,有些博客的时间也是已经很早了,后来google看英文版的才安装成功,这里记录一 ...
- 部署Service Manager 2012遇到的2个问题
上周装了个Service Manager 2012学习,以便完善System Center整个解决方案,在部署期间遇到2个问题,花了我不少时间解决.一.安装时提示“执行自定义操作时失败”每当到了安装的 ...
- 搭建PHP官方框架zend framework 2(LINUX)
在五花八门的语言里,PHP作为我第一个觉得欣赏的理由,就是它的简单和快捷,因为它封装了许多的常用函数.PHP作为网站中一种算作比较流行的语言,也产生各种优秀的框架.我所接触过的有zend framew ...
随机推荐
- Ecshop:ecshop nginx下实现url静态化
1.在nginx/conf/tuwen.com.conf中添加: include ecshop.conf; 2.编辑nginx/ecshop.conf: location / { rewrite &q ...
- Python3+Selenium3+webdriver学习笔记13(js操作应用:弹出框无效如何处理)
#!/usr/bin/env python# -*- coding:utf-8 -*-'''Selenium3+webdriver学习笔记13(js操作应用:弹出框无效如何处理)'''from sel ...
- Android商城开发系列(三)——使用Fragment+RadioButton实现商城底部导航栏
在商城第一篇的开篇当中,我们看到商城的效果图里面有一个底部导航栏效果,如下图所示: 今天我们就来实现商城底部导航栏,最终效果图如下所示: 那么这种效果是如何实现,实现的方式有很多种,最常见的就是使 ...
- UWP开发:应用设置存储
应用设置储存指的是保存在应用程序储存区中的键/值对的字典集合,它自动负责序列化对象,并将其保存在应用程序里.以键/值对方式提供一种快速数据访问的方式,主要用于储存一些应用信息. 1,简介 应用设置是W ...
- 卓越管理的实践技巧(4)如何才能给予有效的反馈 Guide to Giving Effective Feedback
Guide to Giving Effective Feedback 前文卓越管理的秘密(Behind Closed Doors)最后一部分提到了总结的13条卓越管理的实践技巧并列出了所有实践技巧名称 ...
- UVA 10891 Game of Sum (决策优化)
这是一个零和博弈,最高得分只和序列以及谁先手有关. d[i][j],表示i到j的序列当前取的这个人的最高得分,转移以后状态是新的区间和另一个人取,从中取最小值. 决策的最小值也可递推. #includ ...
- ansible 任务委派 delegate_to
ansible 任务委派功能delegate_to run_noce: true 在一个主机上面只执行一次一个任务. ,如果没有这个参数的话,每个playbook中的组的主机都会执行一次. 我们有的 ...
- win7便笺元数据损坏,最新解决办法
Windows7系统开机时出现“部分便笺的元数据已被破坏,便笺已将其恢复为默认值.”问题,最新解决办法,图文说明,亲测,希望可以帮到大家 工具/原料 Windows7系统 InkObj.dll.T ...
- Oracle数据库常用的Sql语句整理
Oracle数据库常用的Sql语句整理 查看当前用户的缺省表空间 : select username,default_tablespace from user_users; 2.查看用户下所有的表 : ...
- sql*plus常用指令介紹
sql*plus常用指令介紹 1.用set指令來設定SQL*Plus的環境參數值 格式: Set 環境參數名 環境參數值 ex:set feedback on set feedback 8.用show ...