dev-master
9999999-devPHP Framework
The Requires
- php >=5.4.0
- filp/whoops *
- symfony/var-dumper *
- catfan/medoo *
- twig/twig <2.0
- vlucas/phpdotenv *
- illuminate/database 5.4.36
- illuminate/pagination *
- illuminate/events *
php php framework
Wallogit.com
2017 © Pedro Peláez
PHP Framework

Thunder,是一个免费开源的,快速、简单的面向对象的轻量级PHP开发框架。, (*2)
project 应用部署目录, (*3)
├─app 应用目录 │ │ │ ├─模块1 项目模块1(例 Home) │ │ ├─common 配置目录 │ │ ├─controller 控制器目录 │ │ └─views 视图 │ │ │ ├─模块2 项目模块2(例 Admin) │ │ ├─common 配置目录 │ │ ├─controller 控制器目录 │ │ └─views 视图 │ │ │ ├─模型1 (例Student.php) │ │ │ ├─模型2 (例Teacher.php) │ │ │ └─ ... ├─core 框架系统目录 │ ├─log 日志及缓存目录 │ ├─public WEB 部署目录(对外访问目录) │ ├─routes 路由配置文件目录 │ └─www.php │ ├─vendor 第三方类库目录(Composer) │ ├─.env env全局配置文件 │ ├─.htaccess 用于 apache 的重写 │ ├─composer.json composer 定义文件 │ ├─index.php 入口文件 │ └─README.md README 文件
http://serverName/index.php(或不写)/模块/控制器/操作/[参数名/参数值...], (*4)
出于优化的URL访问原则,还通过URL重写隐藏入口文件,下面以Apache为例说明隐藏应用入口文件index.php的.htaccess设置。, (*5)
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
RewriteEngine On
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
</IfModule>
如果不清楚命名空间的基本概念,可以参考PHP手册:命名空间, (*6)
模型:namespace app ;
控制器:namespace 模块名 \ controller ;, (*7)
简单来讲,PHP是单继承的语言,在PHP 5.4 Traits出现之前,PHP的类无法同时从两个基类继承属性或方法,php的Traits和Go语言的组合功能类似(可以理解为横向扩展),通过在类中使用use关键字声明要组合的Trait名称,而具体某个Trait的声明使用trait关键词,Trait不能直接实例化。Thunder中的视图层则是利用Trait引入。具体用法请看下面的代码:, (*8)
namespace thunder;
trait View{
public function display(){
//
}
}
namespace Home\controller;
use \thunder\View;
class IndexController{
use View;
public function index(){
$this->display();
}
}
API数据的输出, (*9)
namespace Home\controller;
class IndexController{
public function index(){
$data = ['name'=>'thunder','url'=>'guolifu.pw'];
return ['data'=>$data,'code'=>1,'message'=>'ok'];
//返回纯数组
return ['data'=>$data,'code'=>1,'message'=>'ok','TO_ARRAY'=>true];
//返回jsonp
return ['data'=>$data,'code'=>1,'message'=>'ok','TO_JSONP'=>true];
}
}
{"data": {"name":"thunder","url":"guolifu.pw"},"code":1,"message":"ok"}, (*10)
配置文件位于
core\config中,包括数据库,日志存储,模板后缀,默认路由等配置,还可在分组下的common(如Home\common\config\创建覆盖配置文件), (*11).env作为全局环境变量配置,目前只定义了数据库配置,具体可根据需求使用
getenv()全局获取, (*12)
Thunder中的路由十分简介强大,请看介绍:, (*13)
http://serverName/index.php(或不写)/module/controller/action/param1/value1/param2/value2/..., (*14)
// routes\web.php
use \thunder\Route;
/*注册路由*/
Route::init('goRoute','Home/index/index');
http://serverName/index.php(或不写)/goRoute
<==>
http://serverName/index.php(或不写)/goRoute/Home/index/index
注意!如此注册之后并不代表你可以传递参数, (*15)
需传参写法, (*16)
Route::init('goRoute/{param}','Home/index/index');
http://serverName/index.php(或不写)/goRoute/param1/value1/param2/value2/.../... <==> http://serverName/index.php(或不写)/goRoute/Home/index/index/param1/value1/param2/value2/.../...
Thunder中获取类型是简介明了的, (*17)
http_method()函数获取请求类型, (*18)
IS_GET(判断是否为GET请求), (*19)
IS_POST(判断是否为POST请求), (*20)
route()函数class IndexController{
public function mvc(){
$m = route()->module;
$c = route()->ctrl;
$v = route()->action;
dump('模块:'.$m,'控制器:'.$c,'方法:'.$v);
}
}
在浏览器中访问http://serverName/home/index/mvc, (*21)
"模块:Home" "控制器:Index" "方法:mvc"
一个灵活的框架必然会有一个灵活强大的数据库操作,Thunder为了满足开发者的各种开发习惯,封装了传统操作和ORM操作两种模式。, (*22)
为了避免开发者重复new来new去,系统提供了一个强大的函数table('表名'),你可以把他想象成为一个你即将操作的数据库对象。下面简单了解一下, (*23)
class IndexController{
public function sql(){
table('student')->find(); //默认查找 student 表第一条数据
table('student')->find(2); //返回ID为2的行的
table('student')->find(2,'name'); //返回ID为2的学生的name值(返回字符串)
table('student')->find(2,'id,name'); //返回ID为2的学生的id和name(返回的是数组)
<==>
table('student')->find(2,['id','name']);//为了清晰,可以使用数组形式(推荐)
}
}
class IndexController{
public function sql(){
table('student')->all();//返回student表中全部数据
}
}
where()
class IndexController{
public function sql(){
table('student')->where(['name'=>'thunder'])->find();
table('student')->where(['id'=>1])->all(); //WHERE id = 1
table('student')->where(['id[>]'=>1])->all(); //WHERE id > 1
table('student')->where(['id[!]'=>1])->all(); //WHERE id != 1
table('student')->where(['id[>=]'=>1])->all();//WHERE id >= 1
table('student')->where(['id[<=]'=>1])->all();//WHERE id <= 1
table('student')->where(['id[<>]'=>[1,10]])->all();//WHERE id BETWEEN 1 AND 10
table('student')->where(['id[><]'=>[1,10]])->all();//WHERE id NOT BETWEEN 1 AND 10
table('student')->where('city[~]'=>'lon')->all();//WHERE "city" LIKE '%lon%'
table('student')->where('city[!~]'=>'lon')->all();//WHERE "city" NOT LIKE '%lon%'
table('student')->where('city[~]'=>['lon','foo','bar'])->all();//WHERE "city" LIKE '%lon%' OR "city" LIKE '%foo%' OR "city" LIKE '%bar%'
table('student')->where(["OR" => [
"student_id" => [2, 123, 234, 54],
"email" => ["foo@bar.com", "cat@dog.com", "admin@medoo.in"]
]])->all();
// WHERE
// student_id IN (2,123,234,54) OR
// email IN ('foo@bar.com','cat@dog.com','admin@medoo.in')
// 多条件查询
table('student')->where(["OR" => [
"AND" => [
"user_name[!]" => "foo",
"student_id[!]" => 1024,
"email[!]" => ["foo@bar.com", "cat@dog.com", "admin@medoo.in"],
"city[!]" => null,
"promoted[!]" => true
]
]])->all();
// WHERE
// `user_name` != 'foo' AND
// `student_id` != 1024 AND
// `email` NOT IN ('foo@bar.com','cat@dog.com','admin@medoo.in') AND
// `city` IS NOT NULL
// `promoted` != 1
}
}
class IndexController{
public function sql(){
table('student')->where(["OR" => [
"AND" => [ //实际应用时这儿可以使用AND或者OR
"OR" => [ //第一个条件
"user_name" => "foo",
"email" => "foo@bar.com"
],
"OR" => [ //第二个条件
"user_name" => "bar",
"email" => "bar@foo.com"
]
]
]])->all();
// WHERE (
// (
// "user_name" = 'foo' OR "email" = 'foo@bar.com'
// )
// AND
// (
// "user_name" = 'bar' OR "email" = 'bar@foo.com'
// )
// )
}
}
[>] == LEFT JOIN
[<] == RIGH JOIN
[<>] == FULL JOIN
[><] == INNER JOIN
class IndexController{, (*24)
public function sql(){
table('student')->join(["[>]class"=>['s_id'=>'class_id']])->all();
// LEFT JOIN `class` ON `student`.`class_id` =`s_id`
}
}
//之前的条件查询where()就是连贯操作的一种,剩下的请看例子,非常容易理解。, (*25)
class IndexController{
public function sql(){
//field()筛选字段 参数可以如下写,也可以写做数组形式
table('student')->field('name(别名),num')->all();
table('student')->field(['name','num(别名)'])->all();
//order()排序 参数可写多个,靠前权重高
table('student')->order(['字段名'=>'排序(如ASC,DESC需大写)'])->all();
//limit()条数限制
table('student')->limit(l)->all();//表示从返回结果集中取l条数据;
table('student')->limit([n,m])->all();//表示从返回结果集中的第n+1条开始,取m条数据;
//以上方法均可连贯操作
table('student')->join(["[>]class"=>['s_id'=>'class_id']])->where(['class[>]'=>1])->limit([5,10])->order(['id'=>'DESC'])->field('name')->all();
}
}
public function sql(){
$data = ['name'=>'xiaoming','age'=>18];
table('student')->add($data);
//也可以批量新增
$data = [
['name'=>'xiaoming','age'=>18],
['name'=>'zhangsan','age'=>17],
['name'=>'liergou','age'=>16]
];
table('student')->add($data);
}
public function sql(){
$data = ['name'=>'xiaoming','email'=>'631929063@qq.com'];
//使用update()时可以连贯使用where()作为条件。
table('student')->where(['student_id'=>3])->update($data);
//根据id修改数据时系统提供简介方法
table('student')->setOne(1,$data);
}
public function sql(){
table('student')->destroy(1); //根据id删除数据
table('student')->flushall(); //清空数据表(慎重使用)
}
public function sql(){
table('student')->count(); //统计条数
table('student')->max(); //统计字段最大
table('student')->min(); //统计字段最小
table('student')->avg(); //统计字段平均值
table('student')->sum(); //统计字段求和
}
public function sql(){
table()->query("SELECT * FROM student")->fetchAll();
}
//不是每个数据库引擎都支持事务。你必须在使用前检查。如果返回false,则回滚事务。, (*26)
public function sql(){
$database = table('student');
$database->action(function ($database){
$database->add(['name'=>'事物']);
$res = $database->setOne(1,['name'=>'action']);
return $res->rowCount()==0? false:true;
return false;
});
}
//如果修改没有成功,返回false,则回滚事务。不会修改成功也不会添加成功。
这里的ORM模型就不详细说明了,系统提供了model('表名')函数以供调用ORM模型。具体请移步到https://docs.golaravel.com/docs/4.1/eloquent/, (*27)
Thunder封装了强大的模板引擎供开发者使用。在控制器中use \thunder\View;并且在类中use View;你就可以尽情的使用强大的引擎来协助你的工作, (*28)
class IndexController{
public function index(){
// 模板变量赋值
$this->assign('name','Thunder');
$this->assign('email','Thunder@qq.com');
// 或者批量赋值
$this->assign([
'name' => 'Thunder',
'email' => 'Thunder@qq.com'
]);
// 模板输出
$this->display();
$this->display('index1'); //同级目录下
$this->display('index/url'); //跨控制器输出
$this->display('api/index/views');//跨模块输出
}
}
在tpl配置文件中自定义规则, (*29)
return array(
'TMPL_PARSE_STRING' =>array( //自定义模板变量
'__PUBLIC__' => __PUBLIC__,
'__ADMIN__' => __PUBLIC__.'/'.'Admin',
)
);
//在html中使用{{__PUBLIC__}}调用
{{asset.css('路径')}} //规则:server/public/模块/css/路径;
{{asset.js('路径')}} //规则:server/public/模块/js/路径;
{{asset.asset('路径')}} //规则:server/public/模块/路径;
该方法支持第二个参数, (*30)
{{asset.css('路径',true)}} //规则:server/public/Public/css/路径;代表模块公共目录路径, (*31)
html中使用{{变量名}}, (*32)
{{name}}
在页面中显示, (*33)
Thunder, (*34)
更多模板操作请参考twig手册, (*35)
Thunder的一些其他操作, (*36)
class IndexController{
public function index(){
session()->set('name','val');
session()->get('name');
session()->del('name');
session()->clear();
}
}
use \thunder\Cookie;
class IndexController{
public function index(){
cookie::set('name','val');
cookie::get('name');
cookie::del('name');
}
}
public function create_verify(){
$v = verify();
$v->length = 4; //设置长度
$v->useNoise = false;//是否添加杂点
$v->useCurve = false;//是否画混淆曲线
$v->create();//生成验证码
}
public function verify(){
$code = input('post.code');
$v = verify();
if($v->check($code))
header('Location:./index?login=1');
$this->display();
}
public function upload(){
if(IS_POST){
$up = new \thunder\Upload();
//设置属性(上传的位置, 大小, 类型, 名是是否要随机生成)
$up -> set("path",__UPLOAD__.'/images');
$up -> set("maxsize", 2000000);
$up -> set("allowtype", array("gif", "png", "jpg","jpeg",'xls'));
$up -> set("israndname", false);
if($up -> upload("photo")) {
//获取上传后文件名子
var_dump($up->getFileName());
}else {
//获取上传失败以后的错误提示
var_dump($up->getErrorMsg());
}
}
$this->display();
}
Created by leileida.
v2.0.0
1.修正了路由规则
2.增加了多模块机制
3.控制器方法重构
4.api开发模式,控制器return数组自动转换为json格式等。
, (*37)
5.模型层重构,模型层分离为独立层:
demo:
, (*38)
namespace app;
use \thunder\Model;
class Student extends Model{
public function test(){
return 'test!';
}
, (*39)
6.视图机制优化,支持跨控制器,跨模块输出页面
, (*40)
demo:
, (*41)
namespace home\controller;
use \thunder\View;
class StudentController{
use View;
public function index(){
$this->display();
$this->display('index1');
$this->display('index/url');
$this->display('api/index/views');
}
}
1. fixed the routing rule
2. increased the multi module mechanism
3. controller method refactoring
4. join the API development model, the controller return array automatically converted to JSON format.
, (*42)
namespace app;
use \thunder\Model;
class Student extends Model{
public function test(){
return 'test!';
}
}
, (*43)
namespace home\controller;
use \thunder\View;
class StudentController{
use View;
public function index(){
$this->display();
$this->display('index1');
$this->display('index/url');
$this->display('api/index/views');
}
}
, (*44)
PHP Framework
php php framework