构建自己的PHP框架(视图装载)
2016-12-22 21:06
281 查看
完整项目地址:https://github.com/Evai/Aier
视图装载类要做的工作其实很简单:1.根据视图名称找到视图文件,支持文件夹
2.更加方便,更加优雅地把变量的值传递进视图
本文中我们将不会不引入模板引擎,只做装载文件和传递变量的功能。
基础准备
我们要引入视图装载器,这就正式打开了组件化的大门,所以我们需要做一些准备工作。启动流程组件化
将public/index.php里面的代码分离一部分到启动器(bootstrap),新建MFFC/bootstrap.php文件:<?php useIlluminate\Database\Capsule\ManagerasCapsule; //定义BASE_PATH define('BASE_PATH',__DIR__); //Autoload自动载入 requireBASE_PATH.'/vendor/autoload.php'; //EloquentORM $capsule=newCapsule; $capsule->addConnection(requireBASE_PATH.'/config/database.php'); $capsule->bootEloquent();
修改public/index.php为:
<?php
//定义PUBLIC_PATH
define('PUBLIC_PATH',__DIR__);
//启动器
requirePUBLIC_PATH.'/../bootstrap.php';
//路由配置、开始处理
requireBASE_PATH.'/config/routes.php';
这时候我们就完成了入口文件和启动器的分离,并定义了两个全局常量BASE_PATH和PUBLIC_PATH。
在这里我们需要特别注意一点:“引入路由配置文件”这一步并不只是简单地引入了一个配置文件,路由文件的最后一行Macaw::dispatch();才是真正执行某个控制器中某个function的地方,所有准备条件都应该在载入路由文件之前完成,例如Eloquent的初始化,还有以后我们要使用的Composer包的初始化等等。
引入错误页面提示组件
我们选择修改composer.json:
"require":{
"codingbean/macaw":"dev-master",
"illuminate/database":"*",
"filp/whoops":"*"
}
运行composerupdate,然后将bootstrap.php修改为如下:
<?php
useIlluminate\Database\Capsule\ManagerasCapsule;
//定义BASE_PATH
define('BASE_PATH',__DIR__);
//Autoload自动载入
requireBASE_PATH.'/vendor/autoload.php';
//EloquentORM
$capsule=newCapsule;
$capsule->addConnection(requireBASE_PATH.'/config/database.php');
$capsule->bootEloquent();
//whoops错误提示
$whoops=new\Whoops\Run;
$whoops->pushHandler(new\Whoops\Handler\PrettyPageHandler);
$whoops->register();
下面我们将增加路由配置中无匹配项的错误页面,修改config/routes.php:
<?php
useNoahBuscher\Macaw\MacawasRoute;
Route::get('/',function(){
echo"Welcome";
});
Route::get('/name/(:all)',function($name){
echo'Yournameis'.$name;
});
Route::get('home','HomeController@home');
Route::error(function(){
thrownewException("404NotFound");
});
Route::dispatch();
现在访问一个随意输入的URL,我们会看到以下画面:
是不是有一种很高大上的感觉!(连报错都这么优雅⁄(⁄⁄•⁄ω⁄•⁄⁄)⁄)
实现装载器
完成基础准备以后我们正式开始制造视图装载器。视图装载器是一个可插拔组件,我们应该把所有可插拔组件全部归到一处,在MFFC中建议放在MFFC/services下。
我们并没有像CI框架那样把视图装载器放到系统核心,有以下两个原因:
基于命名空间与自动加载的调用方式更加节省资源
在移动互联网和大前端愈演愈烈的时代,后端越来越API化、json化。很多时候都不到视图,没有必要再增加无畏的消耗。
下面开始着手实现视图装载器。
新建MFFC/services文件夹,并修改composer.json把这个文件夹下的所有类自动归入根命名空间:
{
"require":{
"noahbuscher/macaw":"dev-master",
"illuminate/database":"*",
"filp/whoops":"*"
},
"autoload":{
"classmap":[
"app/controllers",
"app/models",
"app/class",
"services"
]
}
}
新建services/View.php文件,内容如下:
<?php
/**
*ViewLoad
*/
classView
{
constVIEW_BASE_PATH='/app/views/';
public$view;
public$data;
/**
*Viewconstructor.
*@param$view
*/
publicfunction__construct($view)
{
$this->view=$view;
}
/**
*创建视图
*@paramnull$viewName
*@returnView
*/
publicstaticfunctionmake($viewName=null)
{
if(!$viewName){
thrownewInvalidArgumentException("视图名称不能为空!");
}else{
$viewFilePath=self::getFilePath($viewName);
if(is_file($viewFilePath)){
returnnewView($viewFilePath);
}else{
thrownewUnexpectedValueException("视图文件不存在!");
}
}
}
/**
*变量传递
*@param$key
*@paramnull$value
*@return$this
*/
publicfunctionwith($key,$value=null)
{
$this->data[$key]=$value;
return$this;
}
/**
*视图路径
*@param$viewName
*@returnstring
*/
privatestaticfunctiongetFilePath($viewName)
{
$filePath=str_replace('.','/',$viewName);
returnBASE_PATH.self::VIEW_BASE_PATH.$filePath.'.php';
}
/**
*@param$method
*@param$parameters
*@returnView
*/
publicfunction__call($method,$parameters)
{
if(starts_with($method,'with'))
{
return$this->with(snake_case(substr($method,4)),$parameters[0]);
}
thrownewBadMethodCallException("方法[$method]不存在!.");
}
/**
*传输视图及变量
*/
publicfunction__destruct()
{
if($this->data)extract($this->data);
require$this->view;
}
}
运行composerdump-autoload,完成以后,我们就可以在控制器中直接调用这个类了。
修改controllers/HomeController.php:
<?php
classHomeControllerextendsBaseController
{
publicfunctionhome()
{
returnView::make('home')
->with('article',Articles::find(1))
->withTitle('Frame')
->withShowMsg('helloworld');
}
}
修改app/views/home.php:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<metacharset="UTF-8">
<title><?phpecho$title?></title>
</head>
<body>
<divclass="article">
<h1><?phpecho$article['name']?></h1>
<divclass="content">
<?phpecho$article?>
</div>
</div>
<ulclass="msg">
<h1><?phpecho$show_msg?></h1>
</ul>
</body>
</html>
刷新,你将看到以下页面:
至此,视图装载器实现完成。
下面我大致说一下设计视图装载器的基本思路:
这个视图装载器类模仿了Laravel的View类,它实现了一个静态方法make,接受视图名称作为参数,以.作为目录的间隔符。make静态方法会检查视图名称是否为空,检查视图文件是否存在,并给出相应的异常。这就是我们引入异常处理包的原因。
视图名称合法且文件存在时,实例化一个View类的对象,返回。
使用with('key',$value)或者优雅的withKey($value)来给这个View对象插入要在视图里调用的变量。withFuckMe($value)将采用蛇形命名法被转化成$fuck_me供视图使用。
最终组装好的View对象会被赋给HomeController的成员变量$view,这个变量是从BaseController中继承得来。
父类BaseController中的析构函数__destruct()将在functionhome()执行完成后处理这个成员变量:extract出视图要用到的变量,require视图文件,将最终运算结果发送给浏览器,流程结束。
相关文章推荐
- 构建自己的PHP框架(Twig模板引擎)
- 构建自己的PHP框架--抽象框架的内容
- 利用 Composer 完善自己的 PHP 框架(一)——视图装载
- 构建自己的PHP框架--定义ORM的接口
- 构建自己的PHP框架(Redis)
- 利用 Composer 完善自己的 PHP 框架(一)——视图装载
- 构建自己的PHP框架--创建组件的机制
- 构建自己的PHP框架--构建缓存组件(1)
- 构建自己的PHP框架(日志)
- 构建自己的PHP框架(邮件发送)
- 构建自己的PHP框架(ORM)
- 构建自己的PHP框架--构建模版引擎(3)
- 构建自己的PHP框架(MVC)
- 构建自己的PHP框架(composer)
- 构建自己的PHP框架--构建模版引擎(2)
- 构建自己的PHP框架--实现Model类(2)
- 构建自己的PHP框架--构建缓存组件(2)
- 构建自己的PHP框架--实现Model类(1)
- 构建自己的PHP框架--实现Model类(3)