您的位置:首页 > 编程语言 > PHP开发

构建自己的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包的初始化等等。


引入错误页面提示组件

我们选择filp/whoops作为我们错误提示组件包。

修改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视图文件,将最终运算结果发送给浏览器,流程结束。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
章节导航