项目做多了,自然会多多少少的接触各种框架。一个框架可以写的很简单,也可以写的很复杂,国内比较知名的框架是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);
}
}