PHP - Hush Framework 学习记录

PHP

目录

1、PHP 语言的介绍(面向对象,session,MVC 模式)

2、RESTful API 介绍及通信协议制定

3、服务端结构介绍

4、接口程序的介绍

参考资料

《Android 和 PHP 开发最佳实践》

《理解 RESTful 架构》 阮一峰

PHP 语言介绍

PHP(外文名:PHP: Hypertext Preprocessor,中文名:“超文本预处理器”)是一种通用开源脚本语言。语法吸收了C语言、Java和Perl的特点,利于学习,使用广泛,主要适用于Web开发领域。PHP 独特的语法混合了C、Java、Perl以及PHP自创的语法。它可以比CGI或者Perl更快速地执行动态网页。用PHP做出的动态页面与其他的编程语言相比,PHP是将程序嵌入到HTML(标准通用标记语言下的一个应用)文档中去执行,执行效率比完全生成HTML标记的CGI要高许多;PHP还可以执行编译后代码,编译可以达到加密和优化代码运行,使代码运行更快。

1、用于后台脚本编程,即以命令行(CLI)的方式运行

2、用于网络编程,即以 mod_php 或 fastCGI 的方式执行

什么是 CLI

PHP 的命令行模式,用作 PHP 开发外壳应用

什么是 mod_php

简单来说,PHP 使用这种模式让 PHP 代码可以在 Apache 服务器上面运行。

什么是 fastCGI

CGI(Common Gateway Interface) 是一种外部应用程序(CGI程序)与Web服务器的协议,CGI是为了保证Server传递过来的数据是标准格式,

CGI(Common Gateway Interface) 是WWW技术中最重要的技术之一,有着不可替代的重要地位。

CGI全称是“公共网关接口”(Common Gateway Interface),HTTP服务器与你的或其它机器上的程序进行“交谈”的一种工具,其程序须运行在网络服务器上。

fastCGI 则可以看作是升级版的、常驻(long-live)的CGI。

PHP 面向对象开发

面向对象

PHP 语言的面向对象编程思路与其他语言都是非常相似的,对象(Object)、类(Class)、接口(Interface)以及 MVC 三层封装的用法都大同小异。

1、抽象性

对象是面向对象编程的基本元素,对象可以是我们研究的任何元素,可以是具体的物品,也可以是抽象的事物。比如后台管理系统,管理员是一个对象,后台权限也是一个对象。

2、继承性

继承性是面向对象中最基础、最重要的特点之一,也正是因为对象的继承性才衍生出了“抽象”和“封装”等面向对象的设计方法。 PHP 语言中同样使用私有(private)、保护(protected)、公共(public)关键字来设定类、属性、方法的权限。

3、多态性

多态性泛指相同的操作或函数、过程中可作用于多种类型的对象上并获得不同的结果。这个特性进一步增强了面向对象的编程思想的灵活与重用。

class a{
    function test($i){ // $i可以是任何类型的变量
        print_r $i;
    }
}

上例,可以看出由于PHP是弱类型语言,所以$i可以是任何类型的变量,这样一个函数就可以实现如java等强类型语言中靠改变参数类型重载方法的多态形式。

PHP 中的 Session

常说 “不理解会话(session)的概念就等于不懂得 PHP 网络编程”。当然,这里说的 PHP 用于网络编程的时候,因为 HTTP 协议是无状态的,所以每次请求结束之后,变量和资源就回收了,那么我们如何保存一些“持久”的信息呢?比如:用户登录之后,系统需要把用户登录的信息保存下来,在整个应用或者站点里面使用。如果使用数据库来保存,就会很麻烦而且浪费资源,而且又多了很多读写操作,还要定期清理。而且大部分属于临时数据,用户退出登录就没有了,为了解决这些问题,PHP提供了会话模块,来保存这些临时的用户数据。

PHP的session机制不复杂,客户端只需要保存一个Session ID(会话ID),每次会话请求都会把这个 Session ID 传给服务端,并获取服务端接口处理完数据。

PHP 默认的会话存储方法是文件存储,数据都会被保存到服务器本地的 session.save_path 参数设定的目录中。

最简单的具体的使用方法:

首先调用 session_start 方法开启一个新的 session。然后直接使用 PHP 预定义变量 $_ SESSION 来进行读取和存储操作,在请求结束时系统会把修改过的会话值保存到存储器中。

如果多台服务器要共享 session,则需要把 session 集中存储在某个公用的中间件,PHP 的 seesion API 可以供我们控制 Session 存储方式。

MVC 模式

0、 什么是 MVC

MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。

PHP中MVC模式也称Web MVC,从上世纪70年代进化而来。MVC的目的是实现一种动态的程序设计,便于后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能。除此之外,此模式通过对复杂度的简化,使程序结构更加直观。

1、MVC各部分的职能:

模型Model – 管理大部分的业务逻辑和所有的数据库逻辑。模型提供了连接和操作数据库的抽象层。
控制器Controller - 负责响应用户请求、准备数据,以及决定如何展示数据。
视图View – 负责渲染数据,通过HTML方式呈现给用户。

一个典型的Web MVC流程:

Controller截获用户发出的请求;

Controller调用Model完成状态的读写操作;

Controller把数据传递给View;

View渲染最终结果并呈献给用户

协议制定

RESTful

RESTful架构,就是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。

1、名称:

REST,即Representational State Transfer的缩写,”表现层状态转化“

2、资源(Resources):

REST的名称"表现层状态转化"中,省略了主语。"表现层"其实指的是"资源"(Resources)的"表现层"。
所谓"资源",就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实在。你可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI。要获取这个资源,访问它的URI就可以,因此URI就成了每一个资源的地址或独一无二的识别符。

总结:所谓 "上网 ",就是与互联网上一系列的"资源"互动,调用它的URI。

3、表现层(Representation):

"资源"是一种信息实体,它可以有多种外在表现形式。我们把"资源"具体呈现出来的形式,叫做它的"表现层"(Representation)。

比如,文本可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式;图片可以用JPG格式表现,也可以用PNG格式表现。

URI只代表资源的实体,不代表它的形式。严格地说,有些网址最后的".html"后缀名是不必要的,因为这个后缀名表示格式,属于"表现层"范畴,而URI应该只代表"资源"的位置。它的具体表现形式,应该在HTTP请求的头信息中用Accept和Content-Type字段指定,这两个字段才是对"表现层"的描述。

总结:“资源”可以用多种形式表现(一个文本可以用 txt、HTML、XML、JSON 这些格式来表现)

4、状态转化(State Transfer):

访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,势必涉及到数据和状态的变化。
互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生"状态转化"(State Transfer)。而这种转化是建立在表现层之上的,所以就是"表现层状态转化"。
客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。

总结:客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"。

客户端访问服务器时,根据 URI 访问到信息实体(各种文字、图片、视频),客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"

5、综述

(1)每一个URI代表一种资源;

(2)客户端和服务器之间,传递这种资源的某种表现层;

(3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"。
例子:https://www.baidu.com/img/bd_logo1.png

协议制定

0、设计原则

通用性

简洁性

统一

1、通信协议定义

协议的设计是一门艺术,既不能太复杂,也不能太简单;太复杂的话则效率低,太简单则不可以满足需求。之所以选择 JSON 协议作为微博通信协议的基础,就是因为 JSON 协议的简便特性;当然,我们还需要通过设计和加工,把协议制定的更加合理。

基础协议框架

{
    "code" : "正确和错误的代码",
    "message" : "提示信息",
    "result" : "返回内容"
    
}

(1)返回单个对象数据

"result" : {
    "模型名" : {key : value, key : value ... }
}

以上情况适用于仅返回单个模型的情景,比如在用户个人信息界面,我们只需要获取单个用户的个人信息,那么我们就可以使用这种数据的构造形式。

(2)返回对象数组数据

"result" : {
    "模型名.list" : [
        {key : value, key : value ...},
        {key : value, key : value ...},
        ...
    ]

}

以上的数据格式适用于返回一个模型列表的情景,比如在微博列表的界面中,我们需要读取最新若干条微博信息,则可采用这种数组形式的数据来返回多个模型的数据。

(3)返回混合模式数据

"result" : {
"模型名" : { ...},
"模型名.list" : { ...}
}

以上情况适用于比较复杂的组合型界面,在这种模式下,服务端APadliI可以同时返回单个模型数据和模型列表格式的数据

服务端所做的事情,就是把逻辑运算的结果按照协议制定好的格式把数据展示给客户端。

微博实例整体结构介绍:

weibo

客户端:

服务端:HTTP API 接口和 MySQL 数据库之间有一个 “API Debug 后台”,这个组件是我们用来调试服务端的 API 接口用的,因为在服务端和客户端并行开发的过程中我们不可能使用客户端来调试服务端的 API 接口,这样子可以降低调试服务端逻辑的困难。

服务端架构介绍 PHP + MySQL

1、 App MVC

见“接口程序的开发”

2、App‘s Library

本层是应用程序(App)的类库层,App MVC 层的逻辑代码是建立在这个层次之上的。
好处有二:

(1)简化开发,重复编码可以抽象到一起。

(2)加强对重点逻辑的控制,重复逻辑提取出来写入一个方法里,在需要用的地方再调用。

3、Hush Framwwork

Hush Framwwork 是一个PHP框架,微博实例的服务端就是 Hush Framwwork 框架的基础上开发的,包括(Library)

Hush Framework 处理流程一般步骤:

步骤1: 首先,Hush Framework 的请求分发器(Dispatcher)会分析客户端发送过来的 HTTP 请求所包含的信息,并根据请求的 URL 地址来指定使用相应的控制器 (Controller)来处理该请求。

步骤2:接着,被指定的控制器会选择合适的模型类(Model)用于持久层数据的获取和存储,并负责处理该请求的业务逻辑。此外,我们可以看到 Hush Framework 的模型层是基于 Zend Framework 的模型层的。在逻辑处理完成后,控制器还会调用视图层(View)来组合最终的 HTML 代码。

步骤3:最后,服务器会把 Hush Framework 的处理结果通过 HTTP 协议返回给客户端程序来进行后续的处理。

4、Zend Framework 框架 和 Smarty 模版

Zend Framework 是官方的 PHP 框架,适合二次开发,功能强大。

Smarty 模版

  • PHP 语言本身可以嵌入到 HTML 页面中进行数据展现,所以就要写很多<?php ?> 标签,这样就会造成大量的冗余代码,不利于解耦和分离。所以,在项目中,需要有一个专门的模版引擎。

接口程序开发

服务端代码基本目录结构

核心类库分析


1、Demos_App

控制整个服务端应用逻辑的基类,一般来说都是供给应用的入口程序所使用,属于 MVC 层之上的“总控制层”。下面会详细讲

2、Demos_App_Server

是所有API接口以及调试接口的基类,是MVC层中最核心的一部分。参考该类的主要代码(lib/Demos/App/Server.php)

回调方法

此类型的函数包括 __init() 初始化毁掉方法和 __done() 销毁回调方法,在本基类中这两个方法分别负责的是控制器在 “类对象初始化” 和 “类对象销毁” 两个阶段所要做的事情。

公用方法

比如 forward 路径跳转方法以及 render 结果打印方法等。

3、Demos_Cli

用于处理扩展脚本 Cli 编程

4、Demos_Dao

数据库操作对象(DAO),作为 MVC 三层中最接近数据的一层,本示例的代码如下:

    public static function load ($class_name)
    {
        static $_model = array();
        if(!isset($_model[$class_name])) {
            require_once 'Demos/Dao/' . str_replace('_', '/', $class_name) . '.php';
            $_model[$class_name] = new $class_name();
        }
        return $_model[$class_name];
    }   

解释:一个静态方法load用于加载对应目录下的 DAO 类,用于构造数据库表的 DAO 对象

5、Demos_Dao_Core

Demos_Dao_Core 类同样也属于 MVC 三层中的 Model 层的部分,它继承自 Demos_Dao 类,也是 Hush_Db_Dao 的子类

class Demos_Dao_Core extends Demos_Dao
{
    /**
     * @static
     */
    const DB_NAME = 'demos_core';
    
    /**
     * Construct
     */
    public function __construct ()
    {
        // initialize dao
        parent::__construct(MysqlConfig::getInstance());
        
        // set default dao settings
        $this->_bindDb(self::DB_NAME);
    }
}

解释:DAO 的基类,项目中用到的所有的 DAO 类都将继承此类,大部份的 DAO 类中所使用的方法都已经被 Hush Framework 框架封装到了 Hush_DB_Dao 类中。常见的数据库操作方法(增、删、改、查)

6、Demos_Util

应用框架的工具类

Hush Framework 的 MVC 分层思路

1、 控制器 (Controller)
控制器简单来说就是页面的逻辑,在 Hush Framework 中我们通常用 Page(页面)来表示通常意义的 Controller,网络应用 Page 比较好理解。

HF 使用的是 REST 格式的 URL 路径结构,自域名之后的 URL 路径第一个表示的是控制器的名称,第二个则是表示控制器的动作,也就是我们通常称的 Action,比如登陆界面的路径为 “/auth/” ,其对应的逻辑就可以在 AuthPage.php 文件中的 AuthPage 类的 indexAction 方法中找到,这里需要注意的是当前的路径如果为空,我们则会用 index 来替代。

关于接口的 Session

微博应用中的大部分的 API 接口都是要求用户登录的,所以就用到了 Session 会话,对于接口 API 来说,Session ID 是通过 URL 传递的.

DebugServer.php

$configList['action'] = $this->url->format($configList['action']);

这条语句的作用就是把 Session ID 通过 sid 参数附加到 URL 地址中来进行传递。

下面开始在代码上的一些流程,以登录接口为例 :

入口类 server/www/index.php


<?php
require_once '../../etc/app.config.php';
require_once 'Demos/App.php';

$app = new Demos_App();

// 配置应用重要参数
// addAppDir 添加饮用的控制器类库目录,此函数可以被多次调用,每次添加一个类库目录,比如在本应用中就有 API 接口(Server) 和 网页应用(Website)两种控制器的目录,我们都在index.php 中进行设置
$app->setErrorPage('./404.php')
    ->addMapFile(__MAP_INI_FILE)
    ->addAppDir(__LIB_PATH_SERVER)
    ->addAppDir(__LIB_PATH_WEBSITE);

// 将所有的调试信息和错误打印关闭,建议在正式环境关闭
$app->setDebug(true);

// 设置Controller类的类名后缀,使用run方法打开应用程序的运行逻辑,否则页面时不会被执行的
$app->run(array(
    'defaultClassSuffix' => 'Server'
));

解释:代码逻辑的最全面初始化了一个 Demos_App 对象,此对象就是整个应用程序的基类。然后,配置了 404 页面、路径映射文件(用于设定 URL 路由)以及两个控制器类库的路径,这些都是应用程序的必要配置。常量值配置在(etc/app.config.php )

/**
 * App definitions
 */
define('__APP_NAME', 'Demos');
define('__APP_VERSION', '1.0');

/**
 * URL relative constants
 */
define('__HOST_SERVER', 'http://127.0.0.1:8001');
define('__HOST_WEBSITE', 'http://127.0.0.1:8002');

/**
 * MVC url mapping ini file
 */
define('__MAP_INI_FILE', realpath(__ETC . '/app.mapping.ini'));

选取有代表性的微博接口演示:

登陆接口 (http://127.0.0.1:8001/index/login

代码路径:lib/Demos/App/Server/IndexServer.php

loginAction 接口方法对应的是 /index/login 的接口地址,该接口地址会接受从客户端的登陆界面发来的请求,进而完成服务端的登陆动作。实际上,后面所有的服务端接口都是这样使用的。

    public function loginAction ()
    {
        // return login customer
        $name = $this->param('name');
        $pass = $this->param('pass');
        if ($name && $pass) {
            $customerDao = $this->dao->load('Core_Customer');
            $customer = $customerDao->doAuth($name, $pass);
            if ($customer) {
                $customer['sid'] = session_id();
                $_SESSION['customer'] = $customer;
                $this->render('10000', 'Login ok', array(
                    'Customer' => $customer
                ));
            }
        }
        // return sid only for client
        $customer = array('sid' => session_id());
        $this->render('14001', 'Login failed', array(
            'Customer' => $customer
        ));
    }

首先使用 param 方法传入的用户名(name)和密码(pass)参数,然后调用 Core_Customer 类中的 doAuth 用户验证方法进行处理,如果验证成功就把用户信息放入到 Session 会话中。并且返回登录成功,否则失败。

调用的 doAuth 方法的逻辑就是根据用户名和密码到数据表中查找用户的信息,如果有则返回用户信息,若查不到就返回 false。

dbr: db read 的缩写,代表读库。
dbw: db write 的缩写,代表写库。
fetchRow :查找单行,使用该方法进行单行查询,比如查询某哥用户的信息。查询成功则返回多行的用户数据(默认二维数据),失败则返回False。

程序最后都会使用render方法打印 JSON 格式的消息数据。该方法有3个参数,分别是微博通信协议中的 code、message、和 result信息。

微信小程序样例

小程序开发框架的目标是通过尽可能简单、高效的方式让开发者可以在微信中开发具有原生 APP 体验的服务。

框架提供了自己的视图层描述语言 WXML 和 WXSS,以及基于 JavaScript 的逻辑层框架,并在视图层与逻辑层间提供了数据传输和事件系统,可以让开发者可以方便的聚焦于数据与逻辑上。

下面通过一个简单的例子来测试一下登录接口。提供真实的使用场景

推荐阅读更多精彩内容