一、初始化过程

1、94hwan-PHP框架的入口点都是加载根目录的 init.php 来初始化的,因此在这里主要介绍一下初始化时到底做了一些什么。

// 严格开发模式

error_reporting( E_ALL );

//开启register_globals会有诸多不安全可能性,因此强制要求关闭register_globals

if(ini_get('register_globals') )

{

exit('php.ini register_globals must is Off! ');

}

//核心库目录

define('CORE', dirname(__FILE__));

//系统配置

requireCORE.'/../config/inc_config.php';

//外部请求程序处理(路由)

requireCORE.'/req.php';

req::init();

//设置时区

date_default_timezone_set( $GLOBALS['config']['timezone_set'] );

//加载核心类库

requireCORE.'/util.php';

requireCORE.'/db.php';

requireCORE.'/tpl.php';

requireCORE.'/log.php';

requireCORE.'/cache.php';

//debug设置

$_debug_safe_ip= false;

requirePATH_LIBRARY.'/debug/lib_debug.php';

if( in_array( util::get_client_ip(),$GLOBALS['config']['safe_client_ip']) || OPEN_DEBUG === true )

{

$_debug_safe_ip= true;

ini_set('display_errors','On');

}

else

{

ini_set('display_errors','Off');

}

set_exception_handler('handler_debug_exception');

set_error_handler('handler_debug_error', E_ALL);

register_shutdown_function('handler_php_shutdown');

//session接口(使用session前需自行调用session_start)

requireCORE.'/session.php';

/**

* 程序结束后执行的动作

*/

functionhandler_php_shutdown()

{

show_debug_error();

log::save();

if( defined('CLS_CACHE') ) {

cache::free();

}

if( defined('CLS_CACHE_NATIVE') ) {

cls_cache_native::close();

}

}

/**

* 致命错误处理接口

* 系统发生致命错误后的提示

* (致命错误是指发生错误后要直接中断程序的错误,如数据库连接失败、找不到控制器等)

*/

functionhandler_fatal_error($errtype,$msg)

{

global$_debug_safe_ip;

$log_str=$errtype.':'.$msg;

if( OPEN_DEBUG === true ||$_debug_safe_ip)

{

thrownewException($log_str);

}

else

{

log::add('fatal_error',$msg);

header ( "location:/404.html");

exit();

}

}

/**

* 路由控制

*

* @param $ctl  控制器

* @parem $ac   动作

* @return void

*/

functionrun_controller()

{

try

{

$ac= preg_replace("/[^0-9a-z_]/i",'', req::item('ac','index') );

$ac=emptyempty($ac) ?$ac='index':$ac;

$ctl='ctl_'.preg_replace("/[^0-9a-z_]/i",'', req::item('ct','index') );

$path_file= PATH_CONTROL .'/'.$ctl.'.php';

if(file_exists($path_file) )

{

require$path_file;

}

else

{

thrownewException ("Contrl {$ctl}--{$path_file} is not exists!");

}

if( method_exists ($ctl,$ac) === true )

{

$instance=new$ctl( );

$instance->$ac();

}

else

{

thrownewException ("Method {$ctl}::{$ac}() is not exists!");

}

}

catch ( Exception $e)

{

handler_fatal_error( 'init.php run_controller()',$e->getMessage().' url:'.util::get_cururl() );

}

}

/**

* 自动加载类库处理

* 加载优先级 /core/library => 应用目录/model => 根目录/model

* (如果不在这些位置, 则需自行手工加载,对于小型项目,也可以把model全放到library以减少类文件查找时间)

* @return void

*/

function__autoload($classname)

{

$classname= preg_replace("/[^0-9a-z_]/i",'',$classname);

if(class_exists($classname) ) {

returntrue;

}

$classfile=$classname.'.php';

try

{

if(file_exists( PATH_LIBRARY.'/'.$classfile) )

{

requirePATH_LIBRARY.'/'.$classfile;

}

elseif(file_exists( PATH_MODEL.'/'.$classfile) )

{

requirePATH_MODEL.'/'.$classfile;

}

elseif(file_exists(requirePATH_ROOT.'/model/'.$classfile) )

{

requirePATH_ROOT.'/model/'.$classfile;

}

else

{

returnfalse;

thrownewException ('Error: Cannot find the '.$classname);

}

}

catch ( Exception $e)

{

handler_fatal_error( 'init.php __autoload()',$e->getMessage().'|'.$classname.' url:'.util::get_cururl() );

}

}

/**

* req::item 别名函数

*/

functionrequest($key,$df='')

{

returnreq::item($key,$df);

}

说明一:新版框架最大的不同之处是,在引导文件里引入了重新封装过几个重要核心类,这些东西加起来,其实就是组成了最迷你的一个框架,但是功能少却基本完全兼顾,包括下面几个方面:

(1) 路由功能req.php:即是全局环境检查与请求参数初始化;

(2) 基本数据库类db.php:因为数据库类是最常用的的类,因此名称跳出规范的标准,直接使用db作为名称,更便于记忆;

(3) 视图类tpl.php:视图类是MVC框架里不可缺少的东西,本框架通过对smarty进行简化封装后,得到的 tpl 类,即是相当于别的框架的视图对应的功能;

(4) 缓存类cache.php:支持本地单文件hash缓存和memcache缓存,取代原来memcache + 打散文件的模式(这种模式缺点是时间长之后文件碎片极多,造成维护困难);

(5) 日志类log.php:目前仅进行了简单的规范;

(6) 调试程序debug/lib_debug.php:引导文件中定义了debug的方案并且定义了register_shutdown_function接口。

(7) session(sesion.php):重写了session接口,确保在各种场合下都可以使用session。

(8) 引导功能:定义了如何引导到控制器和加载类库路径(un_controller、__autoload)。

说明二:通过分析上面入口源码,必须重点清楚几个事情:

(1)、传入系统的请求参数都是已经转义的,如果需要用到不转义的情况,需要还原后使用;

(2)、对于_GET、_POST、_FILES ,不要再使用原来的操作方法,而是使用 req类去操作(具体可以参考类文档);

(3)、/core/library 目录存放的是系统基础类和公共类文件,不要存放 mod_*.php(如果是很小的项目则没关系),公共接口类要存放这个位置的用 pub_*.php 命名,普通模型类应该存放在 应用目录/model 文件夹,并命名为 mod_*.php (私有逻辑类编程规范里要求用静态成员方法)。

2、分析入口文件 index.php 这里分别把 /index.php 和 admin/index.php 列出来,对比这它们的不同

/index.php

header('Content-Type: text/html; charset=utf-8');

$page_start_time= microtime(true);

require'./init.php';

$config_pool_name=$config_appname=$config_cp_url='';

execute_ctl(req::$forms['ct'], req::$forms['ac']);

?>

admin/index.php

header('Content-Type: text/html; charset=utf-8');

$page_start_time= microtime(true);

require'../init.php';

$config_pool_name='administrator';//应用池参数(与权限管理有关)

$config_appname='admin';//应用名称(与模板文件夹有关,不一定与应用池名称一致)

$config_cp_url='?ct=index&ac=login';//用于未登录用户跳转到的url

cls_template::assign('URL', URL);

//前置的权限控制器

$config_access_ctl= cls_access::factory($config_pool_name,$config_cp_url);

$config_access_ctl->test_purview( req::$forms['ct'], req::$forms['ac'],'1');

execute_ctl( req::$forms['ct'], req::$forms['ac'] );

?>

通过对比,不难看出,admin 目录的入口文件与根目录相比,主要多了如下代码:

$config_pool_name = 'administrator';       //应用池参数(与权限管理有关)

$config_appname   = 'admin';       //应用名称(与模板文件夹有关,不一定与应用池名称一致)

$config_cp_url = '?ct=index&ac=login';     //用于未登录用户跳转到的url

//前置的权限控制器

$config_access_ctl = cls_access::factory( $config_pool_name, $config_cp_url );

$config_access_ctl->test_purview( req::$forms['ct'], req::$forms['ac'], '1' );

上面的代码实际上就是权限控制类的代码,权限控制类通过监听 ct  和  ac 实现对权限的控制的,权限类里对角色分两种情况处理,一种是组权限,在没指定用户具体权限的情况下,通过组权限配置来识别用户权限,在指定了用户具体权限的情况下,以指定的独立权限为准。

此外,细心的人可能会发现 $forms['ct'], $forms['ac'] 居然没预先判断是否存在,实际上其实在 req 类中,对ct和ac为空的情况会默认赋值为 index,当然如果是其它变量,用:

req::item(formName, 默认值)   或直接使用 request(formName, 默认值)

这样获取即可。

二、程序运行过程

通过分析源码,不难知道,程序最终要调用的文件和执行的类及方法,主要在 run_controller() 这函数里处理。

它的源码如下:

/**

* 路由控制

*

* @param $ctl  控制器

* @parem $ac   动作

* @return void

*/

functionrun_controller()

{

try

{

$ac= preg_replace("/[^0-9a-z_]/i",'', req::item('ac','index') );

$ac=emptyempty($ac) ?$ac='index':$ac;

$ctl='ctl_'.preg_replace("/[^0-9a-z_]/i",'', req::item('ct','index') );

$path_file= PATH_CONTROL .'/'.$ctl.'.php';

if(file_exists($path_file) )

{

require$path_file;

}

else

{

thrownewException ("Contrl {$ctl}--{$path_file} is not exists!");

}

if( method_exists ($ctl,$ac) === true )

{

$instance=new$ctl( );

$instance->$ac();

}

else

{

thrownewException ("Method {$ctl}::{$ac}() is not exists!");

}

}

catch ( Exception $e)

{

handler_fatal_error( 'init.php run_controller()',$e->getMessage().' url:'.util::get_cururl() );

}

}

这个函数是通过控制器名称来确定要调用的 control  类文件,并且,初始化这个类,并调用里面的 action(ac) 方法。

PATH_CONTROL == './control'

在上面源码有,有一处语法:empty ( $action ) && $action = 'index';

这种语法是不规范的,倒不是说不合乎PHP标准,而是不具可读性,对于没用过这种方式的人,读起来会很费劲,过于个性化,这是历史留下来的问题,这里我不作修改,让后来人作为反面参考教材。

通过分析源码,相信大家都能明白在94hwan框架下是如何进行开发的了,其实主要是两个方面:

1、URL里的ct 和 ac 表示指向 control/ct_ctname.php 里的 action(ac) 方法,开发人员的工作就是写这个ct类和ac方法,但需要注意的是控制器只负责的用户请求进行控制,逻辑代码应该放在 model 目录的相应类, 或 library 里的框架基础类或项目接口类, 除了lurd类之外,尽量不要在 ac 类直接操作数据库,过于复杂的代码都要封装为逻辑类。

2、框架要求对 GET、POST、FILES 请求都用 req 类,因此,开发前必须先完全弄明白这个类的使用方法。

php框架实现原理,Ylmf-PHP框架基本原理相关推荐

  1. android应用框架与原理之应用框架

    应用框架是在某些特定应用领域中,程序间的共同结构,依共同结构发展程式,使程式具有一致性,增加了程式的清晰性,以降低程式的设计与维护费用. 应用框架与类别库不同 框架发展1.mvc(起源于smallta ...

  2. Ajax框架及原理分析--视频

    Ajax框架及原理分析 下载地址:http://v.51work6.com/courseInfoRedirect.do?action=courseInfo&courseId=240576 AJ ...

  3. 《教育学原理》知识框架整理

    <教育学原理>知识框架整理 一.教育学概述 (一)教育学的概念:教育学是研究教育现象和教育问题,揭示教育规律的科学. (二)教育学的研究对象:教育学以教育现象.教育问题为其研究对象,通过对 ...

  4. Android免Root环境下Hook框架Legend原理分析

    0x1 应用场景 现如今,免Root环境下的逆向分析已经成为一种潮流! 在2015年之前的iOS软件逆向工程领域,要想对iOS平台上的软件进行逆向工程分析,越狱iOS设备与安装Cydia是必须的!几乎 ...

  5. 底层框架_你有必要了解一下Flink底层RPC使用的框架和原理

    1. 前言 对于Flink中各个组件(JobMaster.TaskManager.Dispatcher等),其底层RPC框架基于Akka实现,本文着重分析Flink中的Rpc框架实现机制及梳理其通信流 ...

  6. 这份1307页Android面试全套真题解析,源码+原理+手写框架

    前言 前不久,几个朋友聚会,谈到了现在的后辈,我就说起了那个大三就已经拿到网易offer的小学弟. 这个学弟是00后,专升本进入我们学校的.进来后就非常努力,每次上课都是第一个到教室的,每次都是坐第一 ...

  7. atitit.atiOrmStoreService 框架的原理与设计 part1  概述与新特性

    atitit.atiOrmStoreService 框架的原理与设计 part1  概述与新特性 1. 新特性如下 支持生成sql在无数据库连接的情况下 2. Orm设计 主要的俩个以来service ...

  8. 从零开始实现RPC框架 - RPC原理及实现

    从零开始实现RPC框架 - RPC原理及实现 RPC概述 RPC(Remote Procedure Call)即远程过程调用,允许一台计算机调用另一台计算机上的程序得到结果,而代码中不需要做额外的编程 ...

  9. Asp.net WebPages框架运行原理浅析(转)

    在Asp.net4和4.5中,新增了WebPages Framework,编写页面代码使用了新的Razor语法,代码更加的简洁和符合Web标准,编写方式更接近于PHP和以前的Asp,和使用 WebFo ...

  10. 阿里分布式事务框架Seata原理解析

    阿里分布式事务框架Seata原理解析 作者:伊凡的一天 链接:https://www.jianshu.com/p/044e95223a17 Seata框架是一个业务层的XA(两阶段提交)解决方案.在理 ...

最新文章

  1. Java开发买低压本还是标压本_标压和低压,笔记本怎么选才最香?
  2. perfmon 端口修改_Jmeter 5.3 服务器资源监控插件 PerfMon 使用介绍
  3. Eclipse保存文件时出现字符编码错误
  4. ubuntu下安装windows虚拟机
  5. 基于生成式深度学习方法设计潜在2019-nCoV蛋白酶抑制剂
  6. Effective Java 阅读笔记——方法
  7. oracle 10G windows启动与关闭另类方法
  8. Google research 一行预处理代码,让你的CV模型更强!
  9. 504 Gateway Time-out 错误处理记录
  10. w10系统打印服务器怎样出来,win10怎么打开关闭打印机服务教程步骤
  11. 台式电脑桌面没有计算机图标,电脑桌面上“我的电脑”的图标没了怎么办
  12. 【经验】Namisoft盘点电机扭矩的测量方法有哪些
  13. #原创分享# DDD领域建模---老调新弹之【实体】
  14. 华为云对象存储服务OBS教你一招轻松解决存储难题
  15. vue集成svg-sprite-loader
  16. 锁定计算机时候的屏幕壁纸,电脑锁屏的时候屏幕壁纸怎么更改
  17. 在成都Java培训班学习五个多月有用吗?
  18. java唯一的id_Java:唯一的10位数ID
  19. 通过身份证号计算年龄
  20. UNIT07 BREs EREs PREs

热门文章

  1. docsify-写一个自己的网站
  2. Loose Ends
  3. 见鬼,TSC 编译 TS 文件出现了‘React‘ refers to a UMD global, but the current file is a module. Consider adding
  4. 发那科机器人请关闭电源_发那科机器人报警处理(中文)
  5. 信息系统安全实验(七):使用Kerberos实现网络身份认证
  6. 【百度地图】仅显示中国边界区域
  7. SQL Server菜鸟
  8. TCP/UDP以及端口协议功能
  9. 12.18 Daily Scrum
  10. 计算机系统实验-DataLab