Phpframework
基于mvc设计模式的php框架,单入口的设计,底层组件化的操作,IoC控制实现低耦合。代码简约冗余度小,可读性强,功能稳定可依赖。:rocket:
Install / Use
/learn @fantiq/PhpframeworkREADME
<html>
<head>
<meta http-equiv='content-type' content='text/html;charset=utf-8;'>
<title></title>
<link rel="stylesheet" type="text/css" href="../vertu/stylesheets/init.css">
</head>
<body>
<div class='container'>
<div class='row' style='margin-top: 10px;'>
<div class='col-5 panel' id='side-list-box' style=''>
<a class='item on' href='#overview'>概览</a>
<a class='item' href='#project'>项目</a>
<a class='item' href='#config'>配置文件</a>
<a class='item' href='#parse'>路由解析规则</a>
<a class='item' href='#controller'>控制器</a>
<a class='item' href='#database'>模型/数据库</a>
<a class='item' href='#template'>模版</a>
<a class='item' href='#components'>组件</a>
<a class='item' href='#extend'>扩展</a>
</div>
<div class='col-18 offset-1'>
<a name="overview"></a>
<div class='content'>
<h1>概览</h1>
<h4>1、MVC</h4>
主流的设计模式,分离界面与逻辑,高效的协作开发。
<h4>2、模块化</h4>
采用模块形式组织控制器。解决大型项目文件多、难管理的难题,避免后期迭代文件增多导致代码管理混乱的场面。小项目同样可以采用简单的但模块化的架构组织。
<h4>3、组件式</h4>
框架所有功能都是以组件形式工作,您可以根据自己的需求对各个组件进行改进升华,以适应自己的开发规则,同时可以添加自己的功能组件到框架中,过程简单易用。
<h4>4、易使用</h4>
在控制器以及模型中可以自动的加载所有组件,省去配置、加载等繁琐的操作,一切都是如此简单<span class='tag-def'>$this->组件名</span>
<h4>5、高效率</h4>
框架根据php语言的特性,在特定部分采用单例的设计模式以节省内存的使用。采用控制反转(IoC)的设计模式实例化类,以降低模块之间的耦合度。
<h4>6、数据库</h4>
数据库提供了三种操作形式。1 直接执行sql,2 通过连贯操作组合sql语句,3 ORM操作数据库,简单快捷。
<h4>7、安全性</h4>
1、用户发送的数据全部进行初步检测,并且销毁全局数组,防止一句话脚本的攻击<br>
2、提供数据过滤,清除非打印字符,文件名不合法,XSS字符串。让网站免受跨站攻击<br>
3、防止sql注入,数据库在执行前都会对sql字符串进行合法性检测<br>
4、提供数据格式验证组件,对用户提交的数据类型进行检测,防止数据表字段溢出
5、提供验证码以及表单CSRF防御机制,以应对互联网的'洪水'攻击
</div>
<a name="project"></a>
<!-- 项目 -->
<div class='content'>
<h1>项目</h1>
<h4>创建项目文件夹</h4>
我们创建自己的项目文件夹叫做 <span class='tag-def'>App</span>,然后在文件夹里面创建我们项目需要的各个文件<br>
<ul class='folder-lists'>
<li><i class='icon-folder-open'></i> App</li>
<li class='deep-1'><i class='icon-folder-open'></i> controllers<span class='r'>放置控制器类</span></li>
<li class='deep-1'><i class='icon-folder-open'></i> models <span class='r'>放置模型类</span></li>
<li class='deep-1'><i class='icon-folder-open'></i> config <span class='r'>放置配置文件</span></li>
<li class='deep-1'><i class='icon-folder-open'></i> view <span class='r'>放置模版文件</span></li>
<li class='deep-1'><i class='icon-file'></i> index.php <span class='r'>入口文件</span></li>
</ul>
其他文件夹用户可自行创建,建议您将项目文件(控制器、模型类、配置文件)与可访问的文件(入口文件、图片、css、js)分开存放,并且设置不同的读写权限。
<h4>入口文件</h4>
入口文件内容仅仅需要下面的三行代码
<pre class='code'>
<?php
define('APP_PATH', dirname(__DIR__)); // 指定项目文件夹
include dirname(__DIR__).'/src/App.php'; // 加载框架入口文件
App::run(); // 执行框架
</pre>
<h4>配置</h4>
设置你的配置文件 参照这里 <a href='#config'>配置文件</a>
</div>
<a name="config"></a>
<div class='content'>
<h1>配置</h1>
<h4>配置文件</h4>
下面是配置文件夹的内容:
<ul class='folder-lists'>
<li><i class='icon-folder-open'></i> config</li>
<li class='deep-1'><i class='icon-file'></i> configs.php<span class='r'>核心配置文件</span></li>
<li class='deep-1'><i class='icon-file'></i> rules.php<span class='r'>表单自动验证定义的规则</span></li>
<li class='deep-1'><i class='icon-file'></i> hooks.php<span class='r'>定义的钩子程序</span></li>
<li class='deep-1'><i class='icon-file'></i> datas.php<span class='r'>自定义的配置参数</span></li>
</ul>
具体请参阅源代码中configs.php文件的注释
<h4>主配置文件</h4>
<pre class='code'>
<?php
return [
// 全局的应用程序配置项
'application'=>[
'id'=>'app', // 应用程序的id,项目的命名空间会用到
'timezone'=>'RPC', // 设置时区
'hooks'=>['file'=>'config/hooks.php','class'=>'Hooks'], // 指定钩子程序的位置
],
// 路由配置
// 'router'=>[
// 0 自动识别url
// 1 ?m=Admin&c=Access&a=login&arg1=1....
// 2 Admin/Access/login/arg1/arg2...
// 3 ?r=Admin/Access/login/arg1/arg2...
// 4
'urlmode'=>0,
'defaultController'=>'Index', // 默认控制器
'defaultAction'=>'index', // 默认方法
'modules'=>['Api/WeiXin','Admin'], // 存在的模块名
'regex'=>[ // 正则匹配url规则
'pattern'=>'Index',
],
],
// 数据库配置
'database'=>[
// 'dsn'=>'pdo-mysql://root@127.0.0.1/test',
'dsn'=>'mysql://root@127.0.0.1/test', // dsn形式
'scheme'=>'pdo-mysql', // 数据库类型(pdo类型的要以 pdo-模型 的形式指定)
'host'=>'127.0.0.1', // 地址
'port'=>3306, // 端口
'dbname'=>'test', // 数据库名称
'user'=>'root', // 帐号
'passwd'=>'321321', // 密码
'charset'=>'utf8', // 数据表编码
'prefix'=>'' // 数据表前缀
],
// 内存缓存
'cache'=>[
'dsn'=>'memcache://127.0.0.1:11211', // dsn字符串形式定义
'scheme'=>'memcache', // 缓存类型
'host'=>'127.0.0.1', // 地址
'port'=>11211, // 端口
],
// session
'session'=>[
'auto_start'=>false, // 自动加载
'passwd'=>'321321', // 连接store的密码
// 'dsn'=>'pdo-mysql://root:@127.0.0.1:3306/session/sess_tab',
'dsn'=>'memcache://127.0.0.1:11211', // 字符串形式
'scheme'=>'pdo-mysql', // 存储session数据库的模型
'host'=>'127.0.0.1', // 地址
'port'=>3306, // 端口号
'user'=>'root', // 用户名
'dbname'=>'session', // 存储session的数据库名称
'tbname'=>'sess_tab', // 存储session的数据表名称
'charset'=>'utf8', // 编码方式
'prefix'=>'', // 表前缀
'sess_name'=>'__SESSIONID__',
'sess_expire'=>3600*24, // 默认session过期时间
'alive_time'=>3600, // 用户活跃时间间隔 这个时间内没有任何操作视为下线
'cookie_path'=>'/', // cookie 路径
'cookie_domain'=>'', // cookie 域名
],
// 模版配置
'view'=>[
'drive'=>'template', // 模板引擎
'skin'=>'default', // 默认皮肤
'tpl_ext'=>'php', // 模版文件后缀
'form_hash_name'=>'__hash__', // 表单hash字段名
'form_hash_keys'=>'fantasy', // 表单hash的key
],
/////////////
// 加载用户数据 //
/////////////
'datas'=>include 'datas.php',
'alias'=>[],
];
</pre>
<h4>钩子程序</h4>
默认的钩子程序是在 项目文件夹/config/hooks.php,你也可以在配置文件中指定其他的文件作为钩子程序。
<table class='table'>
<tr class='title'>
<th>#</th>
<th>方法名</th>
<th>作用</th>
</tr>
<tr>
<td>1</td>
<td>preSystem</td>
<td>框架初始化之后调用执行</td>
</tr>
<tr>
<td>2</td>
<td>preRoute</td>
<td>在路由解析url之前调用</td>
</tr>
<tr>
<td>3</td>
<td>preController</td>
<td>在url解析之后,调用执行指定的控制器之前调用</td>
</tr>
<tr>
<td>4</td>
<td>preResponse</td>
<td>在发送内容到用户客户端之前调用</td>
</tr>
<tr>
<td>5</td>
<td>endSystem</td>
<td>整个交互过程完成之后执行</td>
</tr>
</table>
钩子程序中的类继承了Base.class 你在钩子程序中是可以调用所有绑定过的组件的,但是你不能修改钩子程序类中的方法名。
<pre class='code'>
<?php
use framework\base\Base;
class Hooks extends Base{
public function __construct(){
$this->preSystem();
}
// 框架开始执行之前 初始化之前
public function preSystem(){}
// 路由开始解析之前
public function preRoute(){
// echo 'hello';
}
// 路由解析之后 调用用户控制器之前
public function preController(){
// echo "你请求的控制器是:".$this->dispatch->getControllerName()."<br>";
// echo "你请求的控制器方法是:".$this->dispatch->getActionName()."<br>";
}
//发送内容到用户浏览器之前
public function preResponse(){}
框架结束
public function endSystem(){}
}
</pre>
</div>
<a name="parse"></a>
<div class='content'>
<h1>路由解析规则</h1>
框架支持多种的url风格
<ul>
<li><i class='icon-check'></i> ?m=模块名&c=控制器名&a=方法&args....</li>
<li><i class='icon-check'></i> /模块名/控制器名/方法/args....</li>
<li><i class='icon-check'></i> ?r=模块名/控制器名/方法/args....</li>
</ul><br>
模块名是为了指明你的控制器所在的文件夹目录,未指定则指定是 <span class='tag-def'>项目/controllers/</span> 这个目录,指定的话需要你事先在配置文件中 <span class='tag-def'>['router']['modules'] => [模块1,模块2,模块3]</span> 声明。指定模块名的话,框架所调用的控制器文件路径就是 <span class='tag-def'>项目/controllers/模块名/</span> 这个目录了。<br>
比如我们需要访问一个控制器,这个控制器文件所在目录路径 App/controllers/Pay/Taobao/CashController.php 如下图:
<ul class='folder-lists'>
<li><i class='icon-folder-open'></i> App</li>
<li class='deep-1'><i class='icon-folder-open'></i> controllers</li>
<li class='deep-2'><i class='icon-folder-open'></i> Pay <span class='r'>嵌套的模块</span></li>
<li class='deep-3'><i class='icon-folder-open'></i> Taobao <span class='r'>嵌套的模块</span></li>
<li class='deep-4'><i class='icon-file'></i> CashController.php <span class='r'>控制器类文件</span></li>
<li class='deep-1'><i class='icon-folder-close'></i> models</li>
<li class='deep-1'><i class='icon-folder-close'></i> config</li>
</ul>
我们可以知道,要访问的控制器 CashController.php 在文件夹 controllers/Pay/Taobao 下,而 Pay/Taobao 则是这个控制器的模块名。URL中的参数部分应该是这样的 /Pay_Taobao/Cash/index
Pay_Taobao 会被框架自动转义成 Pay/Taobao ,URL中的模块名 控制器名都会被自动转义,规则如下
<table class='table'>
<tr class='title'>
<td style='width:60px;'>URL部分</td>
<td>原来的</td>
<td>转义后</td>
<td>转义规则</td>
</tr>
<tr>
<td>模块名</td>
<td>foo</td>
<td>Foo</td>
<td style='text-align:left;'>在没有 '-' '_' 字符串时,将模块名字符串首字母大写</td>
</tr>
<tr>
<td>模块名</td>
<td>foo_bar</td>
<td>Foo/Bar</td>
<td style='text-align:left;'>对于中间有下划线的,会依据下划线分割字符串,再将每个字符串首字母大写然后用 '/' 将字符串拼接</td>
</tr>
<tr>
<td>模块名</td>
<td>foo-bar</td>
<td>FooBar</td>
<td style='text-align:left;'>对于中间有横线的,会依据横线分割字符串,再将每个字符串首字母大写然后直接将字符串拼接</td>
</tr>
<tr>
<td>控制器</td>
<td>bar</td>
<td>Bar</td>
<td style='text-align:left;'>在没有 '-' 字符串时,将控制器的首字母大写。(所以在类以及类文件的命名规则都要首字母大写)</td>
</tr>
<tr>
<td>控制器</td>
<td>foo-bar</td>
<td>FooBar</td>
<td style='text-align:left;'>对于中间有横线的,会依据横线分割字符串,再将每个字符串首字母大写然后直接将字符串拼接</td>
</tr>
</table>
</div>
<a name="controller"></a>
<div class='content'>
<h1>控制器</h1>
<h4>命名规则</h4>
我们采用流行的驼峰命名法对文件名、类名进行命名规范<br>
控制器文件名首字母要大写且要连接上字符串Controller,后缀为php。比如我们的控制器名称为Index,则文件名为 IndexController.php。若我们要定义的控制器名称是两个单词(customer 、analysis)组成的 则文件名应该是 CustomerAnalysisController.php 。值得注意的是 <span class='tag-warn'>文件名要和类名一致,包括大小写</span>。
<h4>命名空间</h4>
我们采用命名空间对用户的类进行管理,这样您就不必担心类命名
