php 一步步实现mvc架构——view篇
bigsmoker 51future 技术宅
同今天给同学们带了得是"php 一步步实现mvc架构——view篇"。如。掌握设计模式,有利于理解mvc中各种模式得实现。
好了,言归正传。首先先了解下,什么是view 层。还记得 在 路由篇 中得那张图吗?为了更直观一些,我还是将这张图引入

看见那个view层了吧。对得,就是视图层。这个层就是今天得主角。
一 先说说实现思路,来看个view层代码
index.php
======================================================================
<html>
<head>{{$test}}</head>
<body>
<div>{{$myname}}</div>
{{foreach($memners as $k=>$v)}}
<div>{{$v}}</div>
{{endforeach}}
</body>
</html>
这些个奇葩得类似 {{$test}}的变量,就是模板变量,可能有同学说 里面不光是模板变量,还有
{{foreach}}之流,没做。在这个模板里,它们统统都叫模板变量。
再来看下controller层代码
Test.php
======================================================================
function mytestAction()
{
//echo "hello";
//var_dump(func_get_args());
// $this->loadModel('http\models\Test');
$this->assign("test","mytestAction");
$this->assign("myname","hhh");
$this->assign('memners',array('a'=>1,'b'=>'2','c'=>3));
$this->display('index');
}
以上代码代码通过display,去调用 templates.php中的display方法来引用模板。那么这个display是什么鬼?哈哈,其实这个display就做两件事。
1 将index.php中的模板变量解析成 原生php语法
解析前的模板
======================================================================
<html>
<head>{{$test}}</head>
<body>
<div>{{$myname}}</div>
{{foreach($memners as $k=>$v)}}
<div>{{$v}}</div>
{{endforeach}}
</body>
</html>
======================================================================
解析后的模板
======================================================================
<?php $test ='mytestAction'; ?><?php $myname ='hhh'; ?><?php $memners =array (
'a' => 1,
'b' => '2',
'c' => 3,
); ?><html>
<head><?php echo $test?></head>
<body>
<div><?php echo $myname?></div>
<?php foreach($memners as $k=>$v) {?>
<div><?php echo $v?></div>
<?php }?>
</body>
</html>
======================================================================
没错,你可以用任何你能想得到的方法去实现。这里的实现思路就是用正则匹配,替换模板变量
具体实现步骤:
1通过template.php 中的display方法读取模板流
2将模板流中的循环{{foreach($memners as $k=>$v)}}替换成 <?php foreach($memners as $k=>$v) {?>,{{endforeach}}替换成<?php }?>,{{$test}}替换成<?php echo $test?>
3将controller方法mytestAction中的要赋值给模板的值,通过assign($key,$value)的方法赋值给templates.php中的varArr数组。这个vArr形如:vArr["test"]="mytestAction"。
以下是具体操作
给模板赋值
$this->assign("test","mytestAction");
$this->assign("myname","hhh");
$this->assign('memners',array('a'=>1,'b'=>'2','c'=>3));
4将varArr中的值注入模板流
注意
模板流 指用file_get_content,获取的字符串
二 讲完思路,我们上代码,具体看下如何实现
先看下架构图
======================================================================

======================================================================
上图cache 层就是最终引入的php文件(最终的视图模板)
======================================================================
<?php $test ='mytestAction'; ?><?php $myname ='hhh'; ?><?php $memners =array (
'a' => 1,
'b' => '2',
'c' => 3,
); ?><html>
<head><?php echo $test?></head>
<body>
<div><?php echo $myname?></div>
<?php foreach($memners as $k=>$v) {?>
<div><?php echo $v?></div>
<?php }?>
</body>
</html>
======================================================================
再看下http\controller\Test.php
<?php
/**
* Created by PhpStorm.
* User: mario
* Date: 2021/1/26
* Time: 0:39
*/
namespace http\controllers;
class Test extends controller
{
function mytestAction()
{
$this->assign("test","mytestAction");//模板赋值
$this->assign("myname","hhh");
$this->assign('memners',array('a'=>1,'b'=>'2','c'=>3));
$this->display('index');//调用templates/Test/mytest/index.php
}
function mytest3Action()
{
$this->assign("test","mytest3Action");
$this->assign("myname","hello");
$this->assign('memners',array('a'=>1,'b'=>'2','c'=>3));
$this->display('index');//调用templates/Test/mytest3/index.php
}
}
======================================================================
再看下 controller类,调用了Vendor\lib\templates.php的assign和display方法
======================================================================
<?php
namespace http\controllers;
use Vendor\lib\templates;
class controller {
protected $model = null;
private $templatesObj = null;
function __construct()
{
$this->templatesObj = (new templates());
}
function display($name, ...$arguments)
{
$this->templatesObj->display($name, $arguments);
}
function assign($k,$v)
{
$this->templatesObj->assign($k,$v);
}
}
======================================================================
继续查看Vendor\lib\templates.php
======================================================================
<?php
namespace Vendor\lib;
use IFS\Template\Template;
class templates implements Template
{
private $tpl=[];
private $vArr = [];
private $controller;
private $method;
private $suffix;
private $cacheFile;
function __construct()
{
$this->controller=basename(str_replace("\\","/",$GLOBALS['controller']))??'index';
$this->method=str_replace("Action","",$GLOBALS['method'])??'index';
$this->suffix='.php';
}
function display($tpl,$compileDir='')
{
$this->tpl[$this->controller][$this->method] = TPLROOT.DIRECTORY_SEPARATOR.$this->controller.DIRECTORY_SEPARATOR.$this->method.DIRECTORY_SEPARATOR.$tpl.$this->suffix??"";
$pattern = "#{{(.*?)}}#i";
$content = file_get_contents($this->tpl[$this->controller][$this->method]);
$res = $this->replacePattern($pattern,$content);
$compileDir =COMPILEPATH.DIRECTORY_SEPARATOR.$this->controller.DIRECTORY_SEPARATOR.$this->method.DIRECTORY_SEPARATOR;
$this->compile($res,$compileDir,$tpl);
require $this->cacheFile;
}
function assign($k,$v)
{
$this->vArr[$k] = $v;
}
function compile($content,$complieDir,$tplname)
{
$this->cacheFile = $complieDir.$tplname.'.php';
if(is_dir($complieDir))
{
return file_put_contents($this->cacheFile,$content);
} else {
mkdir($complieDir,0777,true);
return file_put_contents($this->cacheFile,$content);
}
}
function setPatternFlag($left,$right)
{}
function parseVar($pattern,$content)
{
preg_match_all($pattern,$content,$matches);
$replacements = [];
foreach ($matches[1] as $k=>$v) {
$matches[0][$k] = '/'.addcslashes($matches[0][$k],'(,$,)').'/';
if(preg_match("#(foreach.*\((.*?)\))#i",$v))
{
$replacements [$k] = "<?php ".$v." {?>";
} else if(preg_match("#(endforeach)#i",$v)){
$replacements [$k] = "<?php }?>";
}else {
$replacements [$k] = "<?php echo ".$v."?>";
}
}
$content = preg_replace($matches[0],$replacements,$content);
$phpVar = '';
foreach ($this->vArr as $k=>$v)
{
if(is_array($v))
{
$phpVar .= "<?php \$$k =".var_export($v,true)."; ?>";
} else {
$phpVar .= "<?php \$$k ='".$v."'; ?>";
}
}
return $phpVar.$content;
}
function replacePattern($pattern,$content)
{
return $this->parseVar($pattern,$content);
}
}
======================================================================
先来看下assign(),很简单,就是将值放入数组,以便将值注入模板流
======================================================================
function assign($k,$v)
{
$this->vArr[$k] = $v;
}
======================================================================
display 函数的作用是将模板变成模板流(file_get_contents($this->tpl[$this->controller][$this->method])),然后调用replacePattern方法将模板流中的模板变量替换成 <?php ?>的形式。用file_put_content方法及将其写入cache/Test/mytest/index.php中。再 通过 require cache/Test/mytest/index.php 加载视图
======================================================================
function display($tpl,$compileDir='')
{
$this->tpl[$this->controller][$this->method] = TPLROOT.DIRECTORY_SEPARATOR.$this->controller.DIRECTORY_SEPARATOR.$this->method.DIRECTORY_SEPARATOR.$tpl.$this->suffix??"";
$pattern = "#{{(.*?)}}#i";
$content = file_get_contents($this->tpl[$this->controller][$this->method]);
$res = $this->replacePattern($pattern,$content);
$compileDir =COMPILEPATH.DIRECTORY_SEPARATOR.$this->controller.DIRECTORY_SEPARATOR.$this->method.DIRECTORY_SEPARATOR;
$this->compile($res,$compileDir,$tpl);
require $this->cacheFile;//引入模板流生成的php文件
}
======================================================================
再来看下最重要的replacePattern方法,这个方法的作用就是替换模板变量{{}}为<?php ?>
然后用compile 方法读取replacePattern出来的流,写入cache对应的目录,如cache/Test/mytest/index.php
效果图
function mytest3Action()
{
$this->assign("test","mytest3Action");
$this->assign("myname","hello");
$this->assign('memners',array('a'=>1,'b'=>'2','c'=>3));
$this->display('index');
}

function mytestAction()
{
//echo "hello";
//var_dump(func_get_args());
// $this->loadModel('http\models\Test');
$this->assign("test","mytestAction");
$this->assign("myname","hhh");
$this->assign('memners',array('a'=>1,'b'=>'2','c'=>3));
$this->display('index');
}

视图层的简单实现今天就讲到这,有兴趣的同学不妨自己试试怎么实现。
相关推荐
-
第18问:MySQL CPU 高了,怎么办?2025-02-24 10:27:18
-
mysql索引类型 normal, unique, full text
mysql索引类型 normal, unique, full text2025-02-24 10:05:05 -
uwsgi+django+nginx 搭建部分总结2025-02-24 10:03:33
-
使用Docker配置Nginx环境部署Nextcloud2025-02-24 10:02:03
-
Nginx安装和怎么使用2025-02-24 10:00:45