php 写一个mvc框架,从零写一个基本的PHP-MVC框架

博主分享了作为PHP新手尝试构建自己最基本框架的经历,包括框架启动、路由解析、URL创建、数据库操作、模型基类、活跃记录、自动验证、缓存、视图渲染、日志记录等关键环节。框架设计参考了CI、Yii和ThinkPHP,实现了传统路由和正则路由,并探讨了正则路由的效率问题。此外,还涉及了数据库操作、模型设计、自动验证功能和缓存机制。目前框架仍处于初级阶段,存在诸多不足,但博主计划通过实践不断改进和完善。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作为入门的新人,PHP框架用的不多。听大牛说,框架何其多,用不完,知道它的基本用法,比如怎么接收路由参数,怎么操作数据库,知道它自带了哪些常用方法或者函数,就差不多了——PHP本来就没太多东西(其实发展到现在已经加了不少了~-~,都用上最新的最先进的,也不简单)。为了理解这个过程更充分一些,尝试着自己也写一个最最最基本的框架,因为要写一个足够好的框架,需要考虑的东西比较多,尤其是可扩展性以及灵活性这两个方面,没有足够经验都不知道这两个“性”是什么东西,还有就是整个框架的设计,没些积累真写不出什么东西来。常用框架里边CI被认为是最简单的(其实也是最古老的框架之一),基本流程是:入口—》路由—》(《缓存》)—》控制器(跟一堆辅助函数以及模型打交道)—》视图(—》缓存)—》浏览器。这确实是最基本最简单的了,而我自己写的这个,也基本是这个流程,并且借鉴了一些Yii Framework和ThinkPHP的做法。

1、框架启动

启动部分,最开始是在入口引入框架启动文件,定义一些路径,读取应配置文件,启动。接着注册自己的自动加载函数,注册错误处理方法以及日志记录等。

2、路由解析

这部分就是难点了,到底要怎样的路由呢?传统的index.php?module=m&controller=c&action=a是不是有点土?使用正则匹配来美化一翻?抑或其他?其实传统路由是最简单效率最高的,正则匹配其实很耗时,尤其是规则多的时候,但为了所谓的美观,还是学一下。至于其他,我目前是不太了解了。因此,我这里有传统路由和正则匹配两种。正则匹配规则如下,左边是浏览器看到的,右边是实际对应的模块控制器方法以及传递的变量。

'rules'=>array(

'index.html'=>'index',

'login'=>'user/login',

'torrent/list//'=>'torrent/list',

'user/name/<.>/age/'=>'user/filter',

'user/sex/<.>'=>'user/filter',

'user/year/'=>array('user/filter', 'urlSuffix'=>'.shtml'),

'thread/'=>array('thread/show', 'urlSuffix'=>'.html'),

),

3、创建URL

这跟路由解析是相反的过程,又一耗时大户,感觉真有点得不尝失。需要根据规则创建能够被解析的URL,而且要传递一定的参数。要传递的参数如果规则中有就得写到规则中的位置,否则就是传统的方法?param1=value1&param2=value2接到规则后边。不知道我的这个处理如何,感觉好麻烦。

4、数据库操作

这一块当然得用上PDO,再用mysql系列估计要被鄙视到火星了。学习了一下基本用法,封装一个Db类,内容倒不是很多。执行查询的方法一个以及执行增删改的方法一个,就差不多了,当然还有个事务操作。

5、模型基类

这是重点之一。很多操作数据库的基础方法都在里边定义,拼接sql、Active Record活跃记录、缓存、自动验证等都在里面定义或是调用的入口。这里面好像刚好达到1000行,对于自己写的东西来说,算比较多的了。

6、活跃记录

英文是Active Record,现在基本的框架都提供这功能,操作数据库就像操作一个对象一样,对于操作单条记录比较方便好用,多条就不行了,每条记录一个对象内存占用高很多的拼接,不如直接拼sql语句来得效率高。一开始不知道这个活跃对象要怎么设计,摸索了很久大体如下,有表名、主键、主键的值、拼sql的各种方法、更改了的数据、查询了的数据、验证场景、查询缓存等等。

object(TestModel)#7 (24) {

["_tableName":"Model":private]=>

string(10) "`students`"

["_fields":"Model":private]=>

array(4) {

[0]=>

string(6) "stu_id"

[1]=>

string(6) "gender"

[2]=>

string(4) "name"

[3]=>

string(8) "class_id"

}

["_pk":"Model":private]=>

string(6) "stu_id"

["_pv":"Model":private]=>

int(3)

["_noPk":"Model":private]=>

bool(false)

["distinct":"Model":private]=>

NULL

["field":"Model":private]=>

NULL

["table":"Model":private]=>

NULL

["join":"Model":private]=>

NULL

["where":"Model":private]=>

NULL

["bindParam":"Model":private]=>

array(0) {

}

["group":"Model":private]=>

NULL

["having":"Model":private]=>

NULL

["order":"Model":private]=>

NULL

["limit":"Model":private]=>

NULL

["active":"Model":private]=>

bool(false)

["chained":"Model":private]=>

bool(false)

["changeProperties":"Model":private]=>

array(0) {

}

["data":"Model":private]=>

array(4) {

["stu_id"]=>

int(3)

["gender"]=>

string(4) "male"

["name"]=>

string(6) "xiaoai"

["class_id"]=>

string(2) "99"

}

["isNew":"Model":private]=>

bool(false)

["scene":"Model":private]=>

NULL

["errors":"Model":private]=>

array(0) {

}

["cacheOptions":"Model":private]=>

array(0) {

}

["doCache":"Model":private]=>

bool(false)

}

7、自动验证

这个简单的写了非空验证、长度验证、数值验证、唯一验证、自定义函数验证、等于某值、不等于某值等简单的验证,其实对这一个的必要性有点疑虑,在控制器之类的自己写也不是很麻烦,但如果需要验证的地方多,也还是有一定用处。对于错误信息的显示还不是很清楚,Yii有个活跃表单之说,把整个模型传递到视图,字段的值与错误信息都通过模型取,打算也这么干。

8、缓存

缓存写了最基本的文件缓存,可以缓存整个页面和sql查询结果,标识分别是url和sql语句。页面缓存可以指定一些url,或者像路由解析一样的符合由module,controller,action,params参数组合起来的规则的页面。

9、视图渲染

这一块Yii写得很复杂,因为它还有Widget挂件这一说法,这个目前不知道怎么实现,也就没搞这么复杂了,直接ob_start之类的就完事了。当然,布局还是有的。

10、日志记录

在调试模式下,系统会记录引入的文件的名称、时间、内存占用、文件路径,一些错误信息,执行了的sql语句以及整个脚本运行的时间。发生错误时用了debug_backtrace追溯调用过程,日志的输出是register_shutdown_function。

目前完成的就是以上这些了,很简陋,其中大部分只是精粗略试了一下能实现而已,实际用的话肯定BUG无数。后面拿它来做个具体的东西再慢慢完善吧。代码push到了github,看官不怕丑可以前往一看:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值