【原创】Zend Framework 2框架之MVC

ZendFramework 2框架之MVC

作者:sys(360电商技术组)

1.前言

Zend Framework 2zend官方推出的php开源框架,基于php5.3,他完全采用面向对象的代码实现,并利用了php5.3的一些新特性,比如命名空间,闭包等。因为是官方的推荐的,今天我们就来学习学习Zend Framework 2,由于本人知识浅薄,也没有实际的用Zend Framework 2做项目开发的经验,有错误的地方还请大家指正,也希望在后面的开发中能用用该框架,此篇文章权当抛砖引玉。


2.体会

相对于我们现在用的QFrameZendFramework 2让我感觉还是相当复杂。可能QFrame我们只用一天的时间,就能完全了解里面的具体实现。但是Zend Framework 2看了几天还是让我无所适从。让我感觉QFrame很实在,很落地,学习使用相对容易,而Zend Framework 2就有点复杂了。Zend Framework 2MVC主要采用了Service Locator和事件驱动的设计模式。他提倡任何类库,扩展等资源都统一被视为服务对象,由一个管理者进行管理,所有服务对象都需要注册给管理者。当应用程序需要某些资源的时候,都从管理者中获取资源。这种方法的好处在于解除了服务调用者和服务提供者之间的耦合。

Zend Framework 2中用了很多设计模式,这一点,是自己需要提高的。在我们实际业务开发中,用的模式比较少,希望在这方面有所加强。

还有一个,我的体会是,Zend Framework 2在编码规范和注释方面做的比较好。这让我想起来了一篇文章,说谷歌为什么严格执行代码规范,大家开可以看看:http://developer.51cto.com/art/201108/283275.htm

这里说说Zend Framework 2的环境搭建以及Zend Framework 2mvc的形式,主要是一些网上和自己的一些使用心得。


3.环境搭建

我是按照官方的教程搭建的。

1.    首先下载Zend Framework 2的框架。从官方网站 http://framework.zendcom/downloads/latest就可以下载到最新的Zend Framework 2框架,我用的版本是2.3.0。将下载的源码放到目录 /home/q/php/ZendFramework 下面。然后修改php.ini添加一个include_path进去 Zend Framework 2_path ="/home/q/php/ZendFramework/library"

2.    搭建开发模板环境。也可以从官方下载示例模板开发环境。官方提供了三种方法安装。网址:http://framework.zend.com/downloads/skeleton-app,第一种是用包的形式,第二种使用Git的形式,第三种是下载压缩包。我用的是最原始的方法,下载压缩包。下载完之后,你把它放到你喜欢的目录。


4.应用示例

好,现在来看一下我们下载的一个示例模板

大概的目录结构就是这样的,入口是public/index.php文件。发现这个结构是不是似曾相识呢。对,和我们现在使用的QFrame很像。下面简单介绍一下各个目录和文件的功能。

文件和目录结构

1.  /public目录

public目录是放cssjsimg等的一下资源文件,public/index.php是项目的入口文件,ngx配置的路径就是这个目录的路径。

public/index.php文件很少

2/init_autoloader.php

        顾名思义,此文件是自动加载类用的。

3/config

        Config目录,是放配置用的。这里,ZendFramework 2又细分了一下application.config.php 这个配置是应用程序级别的配置,是与整个项目有关的,比如需要加载哪些module的配置。/config/autoload/目录下存放的是项目环境有关的配置信息。

4/vendor

        vendor目录一般存放第三方开发的或是自己开发的通用的模块

5/module

        

module目录一般存放当前项目的模块,每个Module就是一个完全独立的功能模块,可以拥有自己的配置文件、语言文件等等。

        /module/Application就是具体的一个module/module/Application/Module.php是此module的配置信息,每个新加的module必须有这个文件。/module/Application/config/module.config.php这里是对路由,控制器等的一些配置。/module/Application/src/里面主要是具体的控制器的实现,/module/Application/view里面主要是tpl文件。

        我们在新加一个module的时候,目录结构也需要是类似的一个形式。


5.技术点解析

上面说到Zend Framework 2采用了Server Locator 和事件驱动的模式,这里我们简单介绍一下ServerLocator和事件驱动

1.  Server Locator

Zend Framework 2中用来实现Server Locator的是 Zend/ServiceManager/这个组件。在Zend Framework 2中,任何的类库,扩展等资源都统一被视为服务对象,并在ServiceManager组件中注册。当应用程序需要某个功能,例如Zend\Log 时,推荐的做法是在ServiceManager中获取,而不是像传统方式那样,include类文件之后再new一个对象出来。这种方式的好处在于解除了服务调用者与服务提供者之间的耦合,作为使用者,不需要知道Zend\Log位置是在哪里,是如何产生的,只需要知道用Zend\ServiceManager::get()这种方式来取得它就行了。

在这里,Zend Framework 2提供了4中注册对象的方法

  • 初始化好的对象

调用setService方法,直接将创建好的对象注册到管理器中

  • 延迟创建对象

调用setInvokableClass方法,其实就是先注册一个类的名字,当需要使用该服务对象时,ServiceManager实例化一个对象给你。

  • 工厂对象

调用setFactory方法,有许多服务对象的产生比较复杂,比如根据配置文件的内容来产生对象等,这时就需要有个专门的工厂来产生服务对象。工厂可以是匿名函数,也可以是实现了Zend\ServiceManager\FactoryInterface的类或对象。

  • 抽象工厂对象

如果要取得一个名字不存在的服务对象时,ServiceManager会去寻找注册的抽象工厂,抽象工厂实现了Zend\ServiceManager\AbstractFactoryInterface,如果有某个抽象工厂的canCreateServiceWithName方法返回true,则 ServiceManager返回该抽象工厂的createServiceWithName方法所产生的对象。

        大致就是这样,这里也是ZendFramework 2为解耦合做的一些努力。

2.  事件驱动

Zend Framework 2初始化的时候,会根据配置注册各类事件并绑定事件处理函数。主要是由Zend\EventManager组件来实现的事件驱动。主要有两个核心文件,Event.phpEventManager.php,一个是事件类(Event.php),一个是事件管理器类(EventManager.php)。这个里面也定义了很多接口以及一些共享事件管理器等。

EventManager类主要负责绑定(attach)事件、解除(detach)事件、触发事件(trigger),在EventManager类内部,维护着一个事件数组,事件数组维护着事件名称与事件处理函数的一对多的对应关系,也就是说一个事件名称可以绑定多个事件处理函数,当事件被触发后,按照绑定顺序,依次执行所绑定的事件处理函数,事件处理函数也被称为监听器(Listener)。在Zend Framework2中实现了一个优先队列,绑定事件的时候,可以给该事件也绑定上执行顺序,这样就能保证在一对多的关系中,你可以设置事件的执行顺序。

Zend Framework 2中预先定义了一些不同的事件对象,如ModuleEventMvcEventViewEventSendResponseEvent等,他们都继承于 Zend\EventManager\Event。这些不同的事件对象所起的作用其实是一样的,都是在事件驱动的工作流程中把事件发生时的上下文信息传递给监听器(Listener),不同之处在于事件发生时的逻辑环境。任何程序在逻辑上总是会有不同的执行阶段的,在不同阶段的上下文环境是不同的,如果用一个事件对象来贯穿所有的执行阶段,必然会在该对象上附加所有阶段的上下文信息,从而导致该对象的臃肿,程序结构也不清晰。因此这里的设计方法就是在不同的逻辑环境中,使用不同的事件对象。

Zend Framework 2在逻辑上把运行过程分成了两个部分,第一个部分是各模块和服务对象的初始化,第二部分是程序的运行。

首先我们来看看/public/index.php 这个入口文件。

主要就三行代码,前面两行主要是autoload,第三行进入程序的运行

Zend\Mvc\Application::init(require'config/application.config.php')->run();

1.  初始化做了些什么

第一步,他产生了一个ServiceManager对象。

ServiceManager初始化的时候默认注册了两个工厂,分别是事件管理器工厂(EventManagerFactory)和模块管理器工厂(ModuleManageFactory)是在Zend\Mvc\Service\ServiceManagerConfig中注册的。

后面我们会看到在另一个类中注册了许多其他的服务对象。事件管理器工厂比较简单,仅仅创建一个事件管理器(EventManager)对象,该对象负责整个MVC流程中所有事件的绑定以及触发。而模块管理器工厂比较复杂,在创建模块管理器(ModuleManager)对象时,还绑定了模块初始化过程中的一些默认事件监听对象(Listener)

接下来是module的加载,

模块(Module)初始化过程中,有四个事件(模块初始化事件)会被触发,依次是:

  • loadModules(开始载入所有模块)

  • loadModule.resolve(单个模块开始解析)

  • loadModule(单个模块开始载入)

  • loadModules.post(所有模块载入完成)

以上这些事件定义在Zend\ModuleManager\ModuleEvent类中。在Zend Framework 2中,为这些事件绑定了许多默认的监听器(Listener),大多数监听器的绑定由Zend\ModuleManager\Listener\DefaultListenerAggregate类完成,它是一个默认监听器的聚合类。在loadModules的时候也绑定了很多监听器,同时也默认注册了很多服务对象。

这样,当初始化阶段完成后,会把所有模块(Module)目录下的ModuleConfig与全局的GlobConfig的内容合并成一个数组,GlobConfig会覆盖ModuleConfig下的同名内容,以Config为名字保存在ServiceLocator对象中,另外在ServiceLocator对象中还有一条为ApplicationConfig的内容,保存的是 config/application.config.php的内容。

2.程序运行

        当个模块初始化完成之后,将进入程序的运行引导,下面这段就是进入程序的引导部分。

        在这里Zend Framework 2将绑定一系列的监听器,比如RouteListenerDispatchListenerSendResponseListenerViewManager

        RouteListener:为route事件绑定一个监听器,主要负责监听解析http请求中的url地址。

        DispatchListener:为dispatch事件绑定了一个监听器,主要是负责监听根据解析之后的url地址,找到对应的controller,然后执行对应的action

        SendResponseListener:为finish事件绑定了一个监听器,该监听器用来产生ResponseEvent对象,并在该对象上触发一系列与发送相应请求(Response)有关的事件。

        ViewManager:这个里面涉及到很多东西,比如:变量的容器(Variables Containers)、视图模型(ViewModels)、视图助手(Helper)、模板(Template)、渲染策略(RenderStrategy)、脚本解析(Reslover)、响应策略(Response Strategy)等,在ViewManager中,为各类绑定了绑定了很多模板处理相关监听器。

        绑定完成之后,开始出发事件的引导事件:MvcEvent::EVENT_BOOTSTRAP,引导完之后就开始执行run()方法,run()方法主要就是触发了四个事件:MvcEvent::EVENT_ROUTEMvcEvent::EVENT_DISPATCH MvcEvent::EVENT_RENDERMvcEvent::EVENT_FINISH。绑定在这些事件上的监听器会负责完成MVC的整个流程。


6.性能效率  

服务器 2U4G

下面是hello world程序,ZendFramework 2的程序流程图:

看上去很复杂的样子,其实本来就挺复杂(另存为可以放大看)。

精简一下,我们再来看看初始化中耗时比较高的一些方法

        从上面的图,我们发现大部分时间花在了mvc的初始化。

下面我们来看看Zend Framework 2QPS

        看这个数据还是挺惨的,QPS感觉有点低,不能充当大任啊。


7.总结

Zend Framework 2在性能方面表现的太让人失望了。但是他的设计理念还是挺好的,但是感觉有点设计过重,初始化的时候做了太多的事情,加载了太多的模块,导致运行效率不高,在实际生产中还是谨慎使用。



-------------------------------------------------------------------------------------

黑夜路人,一个关注开源技术、乐于学习、喜欢分享的程序员


博客:http://blog.csdn.net/heiyeshuwu

微博:http://weibo.com/heiyeluren

微信:heiyeluren2012  

想获取更多IT开源技术相关信息,欢迎关注微信!

微信二维码扫描快速关注本号码:




  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值