MVC框架-路由分发总结

路由的类型 Route Type

无路由 No Route

HTTP请求直接定位到特定的脚本文件执行。比如http://domain/news/latest.php

动态路由

依据某种动态规则进行路由和分发,一般有如下形式:

强约束URL

将Class,function 等信息隐藏在url中,请求来时,依据规则解析URL就可以定位Action函数,比如http://domain/modelName/className/functionName。

优点是简单,缺点是灵活性差,路由信息包含的少,比如拦截器、模版只能在action中写代码调用,不能集中配置。

依据注释信息自动路由

将路由信息,写到执行函数的注释里,请求来时,解析所有action函数的注释,找到合适的,再执行action函数。 Java Spring 和 PHP Symonfy 支持这种路由方式

注释的关键字有(举例)

  • @url
  • @template
  • @filter
  • @trigger

优点是维护起来比路由表简单,缺点是性能较低。

静态路由

路由配置写在配置文件中,依据配置文件,确定如何分发。

路由信息配置在配置文件中,文件或数据格式如下:

  • PHP
  • Yaml
  • Xml
  • Json

笔者最推荐的是 Yaml,因为Yaml 格式的可读性最高,最易于维护。

半静态半动态路由

动态和静态相结合的路由.

尤其是在URL解析中,使用正则匹配的路由方式。

路由的组成 Route Components

路由分发的元素

  • URL , URL特征决定分发到特定Action函数
  • Action 函数,函数所在的class、Namespace
  • 模版 template ,页面渲染的模版
  • 拦截过滤器,Filters , 比如权限检查、地区检查、无效请求检查等各类filter
  • 触发器,triggers , 页面调用后触发的操作

URL 的组成

URL 包含着路由的关键信息,决定请求分发到具体的Action函数

MVC 框架的 URL 一般由下列部分组成

  • 域名 domain name
  • 模块/目录 model/directory name
  • 功能 function name
  • 参数 parameter

参数有两种形式存于http请求中,一种是作为POST和GET方法的参数,一种是直接在URL中。

Route Style

Restfull 的路由分发

遵循Rest 风格、规范的URl

普通的路由分发

企业应用架构之分层 – 总结

常见分层架构模式

三层架构 3-tier architecture

微软.net 体系推荐的分层结构,因此早期在C/S架构和ASP编码的系统中被广泛应用,同时也被其他语言广泛借鉴。

表现层, Presentation Layer(PL)

主要负责数据的输入接口和输出。输入指在WEB、客户端或为外界提供的API的数据请求接口;输出则是Web界面、客户端输出、API的数据输出。

页面模版、 对外API数据格式化、Request接受 、Output推送、 Commander操作都在这一层。

业务逻辑层, Bisiness Logic Layer(BLL)

主要负责从原始数据到结果数据的中间过程。系统中最关键、中重要的一层。也被称作领域层(Domain Layer),领域中所有对象的逻辑关系和功能实现算法都在这一层中。

业务逻辑、服务等处于这一层。

数据访问层, Data Access Layer(DAL)

主要是对原始数据的操作层(CRUD操作),为业务逻辑层或表示层提供数据服务。数据源包括,数据库、文件、网络存储系统、其他系统开放的API、程序运行上下文环境等等。

许多框架中的ORM 、 Active Record 、 Dao 类或库都处于这一层。

三层架构总结

三层架构能较好的满足大部分的业务场景,实现高内聚、低耦合。不同层次之间逻辑解耦或者隔离,变为弱依赖,每层的逻辑内聚。从层次角度看,使系统有了较好的可扩展性。

三层架构的不足有:

  • 业务逻辑复杂度高的系统,业务逻辑层将变得庞大臃肿,为了解决这个问题,四层架构/多层架构被人提出。
  • 不关注表现层的实现。

四层架构 4-tier architecture

四层架构和三层架构极为类似,分为表示层、服务层、业务逻辑层、数据访问层。除了服务层,其他三层和三层架构的三层几乎一致,而服务层,是对三层架构中业务逻辑层的再细分,以解决业务逻辑层经常出现的臃肿的问题。

四层架构是Java EE(J2ee) 推荐的分层架构,尤其是Java Spring+Struct+Hibernate(SSH)组合的框架 将Dao层、 Service层,做了明确的定义和规范。由于SSH框架被广泛使用,其他框架,包括其他语言的框架(比如PHP)也都借鉴SSH,因此在这些框架里能看到Dao类、Service类的抽象定义。

服务层, Service Layer

在三层架构中,把业务逻辑层的上层逻辑分离出来,组成服务层。服务层往往是逻辑的表示层,即向上层(表示层)提供逻辑的外观。事务控制、安全检查、事务脚本等可以置入业务层(参考Martin fowler 的《企业应用的架构模式》)

四层架构总结

四层架构是三层架构的发展或进化。服务层的出现让三层架构的业务逻辑层不再变得臃肿。

四层架构和三层架构都存在一个不足,就是不强调前端的实现。当面对需要个性化定制界面、复杂用户交互、页面之间有依赖关系时,需要更好的解决方案。

MVC 模式

MVC 模式最主要包括三部分,Model View Controller(模型-视图-控制器)。

相比于三层架构或者四层架构,MVC最突出的优点是前端控制的灵活性。如果把MVC的View和Controller剥离出来,实际上是一种叫前端控制器模式的设计模式。

MVC 的缺点很明显,将前端以外逻辑都放到 Model里,随着业务增多,Model将越来越难以维护。

MVC 并不适合称作一种分层架构,更适合称为一种复合的设计模式。有人还将MVC模式归类为前端架构。

为什么MVC模式被广泛的采用? 笔者是这样认为的:

  • MVC模式最适合新闻门户网站、展示类网站,此类网站业务逻辑往往较为简单。
  • MVC模式最适合产品初创时被使用,因为项目初期逻辑简单, 使用MVC模式产品能快速成型,可以尽早投放市场进行试验(多数可能会被淘汰),这样就降低了试验成本。(如果产品有潜力,中后期随着业务增多和变得复杂,系统必然面临重构压力。)
  • MVC模式最适合产品原型的实现(注重前端)。

其他分层架构

除了三/四层架构,MVC模式,还有很多架构模式,但这些多是与三/四层架构、MVC模式类似,或是在他们之上进行扩展和改造。比如 MVVM (Model-View-ViewModel)、MVP、DDD架构模式等。

关于分层的总结

分层的思想或目的

  • 高内聚
  • 低耦合
  • 增强系统的可扩展性
  • 增强系统的可维护性

分层的优点

  • 开发人员可以只关注整个结构中的其中某一层;
  • 可以很容易的用新的实现来替换原有层次的实现;
  • 可以降低层与层之间的依赖;
  • 有利于标准化;
  • 利于各层逻辑的复用;
  • 结构更加的明确;
  • 在后期维护的时候,极大地降低了维护成本和维护时间

分层的缺点

相比于分层的优点,分层的缺点显得微不足道。

  • 使用分层虽然增多了代码量,但清晰的架构和代码复用却降低了开发成本、维护成本。
  • 分层虽然在逻辑上增多了代码的调用、增多了逻辑分支,降低了性能,但是这部分降低的性能与系统中真正的性能瓶颈(存储IO、网络IO、高层次的语言)相比,显得实在渺小。
  • 分层有时会导致级联的修改,但这种情况是可以通过面向接口的设计或者使用中介者模式、门面模式、适配器模式等设计模式解决。

如何设计分层架构

  • 软件的发展都是遵循着从简单到复杂的过程,软件架构也是一个迭代的过程,是一个循序渐进,不断完善的过程。简而言之,不断地重构。
  • 借鉴或者直接使用Java EE(j2me)的分层规范,并使用dao、service等类的命名。
  • 层与层之间交互部分,要遵循面向接口设计的原则,不吝舍使用设计模式。
  • 分层的选择要平衡成本和风险,使收益最大化。
  • 业务逻辑不要局限于四层架构或三层架构,依据领域业务特点可更细地划分层次。

PHP Native Interface

本页面转自: https://github.com/zuocheng-liu/pni/blob/master/README-zh.md

PNI github PAGE : https://github.com/zuocheng-liu/pni

什么是 PHP Native Interface (PNI) ?

  • PHP 的一个C扩展
  • 通过它,可以让PHP调用其他语言写的程序,比如C/C++、汇编等等
  • 需要PHP来调用,但PHP有限使用的领域里,PNI可以发挥用处,比如图像处理、统计学习、神经网络、实时性要求高的程序等等

使用场景

PHP 不是完美的语言,总有一些情况下,不得不使用其他语言来协助完成。在这些特殊的场景下,使用PNI就可以将PHP与其他语言连接起来:

  • 实时性要求特别高的程序,特别底层的程序
  • 用其他语言写的程序,历史遗留下来的程序,如果用PHP重新实现成本太高的程序或逻辑
  • 基于平台特性的代码,不能用PHP实现的程序
  • 调用系统的动态链接库

与直接编写PHP扩展相比

直接编写PHP扩展去调用其他语言的接口是常用方法,不过PNI有更多的好处:

  • 降低开发和运维成本

不需要每次有新的需求,就去编写或改动PHP的扩展。对PHP扩展的开发、调试会占用很多的时间。

PHP扩展更改后上线,需要重启PHP服务,这是有一定风险的。

如果使用PNI,就会便捷很多,对新功能的开发和上线,只需操作PHP的代码即可。

  • 降低学习成本

开发PHP扩展,需要开发人员去学习 PHP-API、 Zend-API 、 PHP扩展框架,甚至需要深入去理解PHP内核。
有了PNI,问题就简单多了。

  • 灵活性

使用PNI,可以更灵活地使用本地类库。

使用手册

类和方法列表

  • PNIFunction

方法类,此类定位动态链接库中的函数名
php
$pow = new PNIFunction(PNIDataType::DOUBLE, 'pow', 'libm.so.6');

上面的例子,在构造函数中,第一个参数是需要找寻函数的返回值类型,第二参数是函数的名字,第三个参数是到那个动态链接库中找寻函数。

  • PNIException

异常类,在无法找到动态链接库或函数名的时候,会抛出异常。

数据类型类

  • PNIDataType
  • PNIInteger
  • PNILong
  • PNIDouble
  • PNIFLOAT
  • PNIChar
  • PNIString
  • PNIPointer

所有数据类型类都继承PNIDataType抽象类,此抽象类包含3个共有方法

php
getValue(); // 获取值
setValue($value); // 重新赋值
getDataType(); // 获取数据类型

PNIString 和 PNIPointer 中还额外包含一个接口

php
systemFree();

用于释放C函数中malloc申请的内存资源。
强烈不推荐使用PNI直接调用这样的库函数。

定义的常量

表示数据类型常量
php
PNIDataType::VOID
PNIDataType::CHAR
PNIDataType::INTEGER
PNIDataType::LONG
PNIDataType::FLOAT
PNIDataType::DOUBLE
PNIDataType::POINTER

示例

示例 1 , 调用系统接口 :

php
try {
$pow = new PNIFunction(PNIDataType::DOUBLE, 'pow', 'libm.so.6');
$a = new PNIDouble(2);
$b = new PNIDouble(10);
$res = $pow($a, $b);
var_dump($res);
} catch (PNIException $e) {
}

上面例子,使用PNI调用系统math库中的pow函数

示例 2,调用自己定义的C/C++ 逻辑 :

  • 1.构建C程序

C++
// file user_math.c
u_int32_t sum(u_int32_t a, u_int32_t b) {
return a + b;
}

– 2.创建动态链接库,并把它放到 $LD_LIBRARY_PATH 包含的目录里
shell
gcc -fPIC -shared -o libusermath.so user_math.c

– 3.创建PHP程序

“`php
// file testPni.php
<?php
try {
$sum = new PNIFunction(PNIDataType::INTEGER, ‘sum’, ‘libusermath.so’);
$a = new PNIInteger(2);
$b = new PNIInteger(10);
$res = $sum($a, $b);
var_dump($res);
} catch (PNIException $e) {
}

“`
– 4.执行PHP程序

shell
$ php testPni.php

$res 是 PNIInteger类型,其中包含数值结果为12的成员变量

PNI 数据类型类和C语言数据类型对照

PNI 数据类型类 C 数据类型 说明
PNILong long int/ int PHP has no unsigned int
PNIInteger long int/ int PHP has no 32bit Int
PNIDouble double / float
PNIFloat double / float PHP has no 32bit float
PNIChar char
PNIString char*
PNIPointer char*

由于PHP只有64整形,所以PNILong 和 PNIInteger 实际上是等效的。

如果通过PNI调用的函数参数类型是32位、16位数据怎么办?需要开发人员保证PNILong和PNIInteger存放的值不能超出大小。

PNIDouble 和 PNIFloat 也是等效的,因为PHP只有64位浮点。如果调用的C函数参数列表里有32位浮点呢? 不用担心,即使是32位的浮点,在x86_64架构的CPU里,也是赋给了64位的浮点运算器。

缺点或注意事项

  • 目前还不支持PHP7 ,但作者会争取尽快开发适用PHP7版本的PNI
  • 如果PHP是多线程运行,需要注意PNI调用的动态链接库是否是线程安全的
  • 对于在动态链接库中申请的资源,要及时释放
  • 目前PNI还不支持对复杂数据类型的操作,比如struct,C++的类等

如何安装

环境要求

  • PHP 5.3 以上版本, 但不包含PHP 7
  • 必须是GCC编译器
  • CPU 必须是x86_64架构或被兼容的架构

安装步骤

  • 下载

shell
git clone https://github.com/zuocheng-liu/pni.git

– 编译和安装

shell
cd <src-pni>
phpize
./configure
make && make install

– 配置PHP,使其生效

把下面一行添加到 php.ini

shell
extension=pni.so;

– 重启PHP服务

bash
service php-fpm restart // cgi mode
apachectl restart // sapi mode
// do nothing in cli mode

开发

提出建议和提交Bug

热盼您的联系!

其他

网址

联系方式

协议

version 3.01 of the PHP license.(see LICENSE)