项目做多了,自然会多多少少的接触各种框架。一个框架可以写的很简单,也可以写的很复杂,国内比较知名的框架是TP,也有超轻量级的框架speedPHP.
这里,将一个非常框架的编写思路,做个简单记录,想写框架的可以在看了一个简单框架思路后,也尝试自己写一个框架(虽然不会有很大的实用价值,但是还是可以锻炼一些思维的)。
1.需要定义一些常量,一般定义框架或者核心文件的路径,比如:
Define(‘XPHP_PATH’,__DIR__);
作为变量的扩充,可以增加一些其他路径的定义。这里首先定义了框架的核心目录,就是定义文件当前的路径。
2.需要定义自动加载的路径,在框架里面,自动加载是一个非常重要的函数,自动加载使得框架很容易扩充系统本身的类和方法。
set_include_path(XPHP_PATH.’Controller’ . PATH_SEPARATOR . get_include_path());
set_include_path(XPHP_PATH.’Model’ . PATH_SEPARATOR . get_include_path());
set_include_path(XPHP_PATH.’View’ . PATH_SEPARATOR . get_include_path());
把mvc的文件夹分别写到当前目录下面。
3.写个自动加载函数。因为在上面,系统会自动去寻找目录。
function loader($file) {
include $file . ".php";
}
spl_autoload_register('loader');
这里用了SPL函数,实际上如果简单,并不需要接入外部开发的情况下,可以直接用__autoload 自动加载函数。这样,已经默认将include的路径里面的文件全部加载到了当前文件夹,可以随时进行调用。 否则需要对文件一个一个的去include(当引用文件上百个,是一个非常麻烦的事情)
4.因为已经把我们需要的文件全部引入到了当前文件。首页被访问的时候,需要对路由进行分发访问,在老的php文件中,直接通过访问php文件的方式获取访问接口,但是我们现在开发的是单入口,就需要参数来进行调度了.
最简单的参数调度,我们假设访问路径设置为index.php?c=test&a=index的方式,本意是访问到testController控制器里面的index方法(当然也可以设置其他的路由解析方法,这里我们用了默认的路由解析方法)
parse_str($_SERVER["QUERY_STRING"], $arr); 用这个函数,把后面的变量重组到一个数组中。
这样c和a编程了$arr[‘c’]和$arr[‘a’]俩个变量
5.我们已经从外部的访问里,得到了路由访问的意图,就是想访问test控制器里面的index方法。设置下$a = $arr[‘a’];$c =$arr[‘c’]
$controller = new $c();
$c->$a();
这里直接将变量作为参数,进行实例化,这样外部传入的俩个变量,直接变为了控制对应控制器的action的操作。
6.一般为了安全起见,会对每个非入口直接访问对应的php会加上一个警告
If(!definded(‘XPHP’)) header(‘Location://’);
这样访问任何没有授权的目录的文件的时候,都会自动跳转到默认的首页访问。
7.基本的路由解析和分发,还有自动加载完成了,基本上一般我们使用的框架模式,就是这种。然后会对功能进行各种拓展。
我们需要写三个额外的基础方法一般是ControllerBase;ModelBase,ViewBase。这三个基础方法,主要封装我们框架的一些共性使用。
然后在开发的每种文件里继承自己对应的基类,就可以开始进行开发。
8.基本的雏形设置后,如果需要引入数据库,一般需要增加额外的config.php文件,一般用来配置数据库和一些设置。然后同时需要引入mysqlDb.class.php (这个类基本是封装一些常用的mysql操作类)因为我们本身框架很简陋,我们仅仅需要封装简单的CURD功能就可以(TP封装了大量的自身方法,方便入门的同时,也加重了PHP执行的负担)
9.最后,由于我们在访问的时候,经常会有各种访问错误(访问错误需要进行友好的提示)PHP本身的提示是不友好的,很容易暴露我们使用的PHP版本等信息。需要加入一个错误控制,(当然,也可以用错误捕捉try..catch)set_error_handle(‘’) 该函数的用法和SPL函数一样。
10.这样,一个初步的MVC框架模型已经出来了。如果仅仅是测试使用,你已经可以将其用在自己内部访问的项目上。
下面是一个MVC样例:(代码放在一个文件里)
<?php //定义版本号 define('XPHP_VERSION', 1); //打印开发函数 function p($val) { echo "<pre>" . print_r($val, true) . "</pre>"; exit; } /** * PHP脚本执行后退出时候执行的函数 */ function endExc() { return ''; } /** * 输出字段映射转换 * */ function tranfer($str1,$str2) { $arr1 = explode(",",$str1) ; $arr2 = explode(",",$str2) ; $ct = count($arr1); for($i=0;$i<$ct;$i++) { $rtarr[]= $arr1[$i].' as '.$arr2[$i]; } $rtstr = join($rtarr,","); return $rtstr; } //定义核心目录与路径 define('SYS_PATH', dirname(__FILE__) . "\\"); define("XPHP_PATH", SYS_PATH . 'xphp\\'); //将核心目录写入默认路径 set_include_path('sys/xphp' . PATH_SEPARATOR . get_include_path()); //自动加载函数(没有指定路径的情况下 会自动从include的路径中对文件进行加载) function loader($file) { include $file . ".php"; } spl_autoload_register('loader'); register_shutdown_function('endExc'); //set_error_handler('errFun'); //解析路由器 parse_str($_SERVER["QUERY_STRING"], $arr); if (@$arr['c']) { $c = $arr['c'] . "Controller"; } else { $c = 'BaseController'; } if (@$arr['a']) { $a = $arr['a']; } else { $a = 'index'; } //全局变量设置数据库 $_Xconfig = array( 'DBHOST' => 'localhost', 'DBNAME' => 'mysql', 'DBUSER' => 'root', 'DBPWD' => 'root', ); $config = array( 'test'=>'12' ); //递归合并配置 function MergeRecursive(&$arr,&$arr2) { foreach($arr2 as $key=>$value ) { if(isset($arr[$key])&&ia_array($value)&&is_array($arr[$key])) { $arr[$key] = MergeRecursive($arr[$key],$arr2[$key]); } else { $arr[$key] = $value; } } } MergeRecursive($_Xconfig,$config); //路由分发 $xphp = new $c(); $xphp->$a(); /** * 基础框架类 */ class BaseController { public function index() { echo "Welcom To XPHP World"; } public function test() { $model = new BaseModel(); $model->test(); } } /** * 基础model,链接mysql */ class BaseModel { public function test() { global $_Xconfig; $host = $_Xconfig['DBHOST']; $dbuser = $_Xconfig['DBUSER']; $pwd = $_Xconfig['DBPWD']; $sqlModel = new MysqlDbModel(); $xcon = $sqlModel->xconnect($host,$dbuser,$pwd); //字段映射 $str = tranfer("host,user","ip,name"); $arr = $sqlModel->select("select $str from mysql.user limit 1"); print_r($arr); $funName =__FUNCTION__; BaseView::display($funName); } public function add() { } } /** * 基础模板引擎设置 */ class BaseView { public static function display($pathname) { @require 'view//'.$pathname.".php"; } } /** * 基础的mysql数据操作model * */ class MysqlDbModel { public $xcon = ''; /** * 数据库的连接 * @param type $hostname * @param type $username * @param type $passwrod * @return type */ public function xconnect($hostname, $username, $password) { //在php5.5以后继续使用该方法会提示一个不安全的警告错误,如果继续使用,需要@将该行错误关闭 $this->xcon = @mysql_connect($hostname, $username, $password); return @mysql_connect($hostname, $username, $password); } /** * 对不同的数据库连接进行执行 * @param type $sql * @param type $xcon */ public function query($sql) { $res = mysql_query($sql, $this->xcon); return $res; } /** * 读取多行数据进行列表查询 * 返回对应的数组 * @param type $sql * @return type */ public function select($sql) { $rtArr = array(); $res = $this->query($sql); while ($list = mysql_fetch_assoc($res)) { $rtArr[] = $list; } return $rtArr; } /** * 关闭数据连接的时候进行使用 * */ public function close() { mysql_close($this->xcon); } }