用 php 实现一个视图组件和模板引擎——基础
只要不是做后端接口开发和一些作为守护进程之类的服务器脚本,大多数时候都是在和浏览器打交道,因此合理组织并展现 html 标签是最为常见的工作。一般大家使用框架时,都会自带有一套视图组件和模板引擎。
我们不讨论这些组件和引擎的好坏。因为这些东西已经经过考验,可以在生产环境下使用。我们现在只是为了学习一些东西,这时候了解一些原理上的可能对以后的帮助更大,如果一些人真的很有时间,利用这些基础知识完全可以写一个自己的组件,即可当做练习,也可以拿去自用。
好了,说这么多,我还是希望很多人明白,视图和模板引擎实际上原理十分简单,所涉及的知识可以说是太基础不过的了。但,千万不要把视图和模板引擎搞混淆,这两个真的不是一个东西 。
为了理解这些,我们先从视图开始了解。
视图
视图,你所看见的部分。
<?php
echo 'hello, world';
从简单开始理解
这就是个视图文件中的代码,没错就这么简单。视图,实际上是在 MVC 这种架构上提出的。MVC 中,视图负责呈现数据。因此可以说只要是输出了数据的,都叫做视图。
在没有使用框架的时候,业务逻辑、数据的读写、组织和展示都是在一堆代码里,难以剥离,随着项目增大变得越来越难以维护。MVC 有效的分离了三者,各司其职。视图作为呈现数据的,只负责组织、展示,不再负责读写和业务逻辑。
既然视图只负责呈现数据,那么单独成一个文件,这个文件内的代码绝对不要读取数据库、做业务判断,那么就算你将视图独立出来了。这时候大多数人会想到,视图中的数据从哪来呢?
我们以一个简单的例子实现一个业务逻辑和视图分离的结构。
文件 controller.php,代码如下
<?php
$time = time();
$string = ($time % 2) == 0 ? '偶数' : '奇数'; // 加载视图
include 'view.php';
文件 view.php,代码如下
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>视图实例</title>
</head>
<body>
<p>时间戳 <?=$time?> 是 <?=$string?></p>
</body>
</html>
代码写好,运行后结果是预期的,对吗?
这两个文件中,毋庸置疑 view.php 就是视图文件,而 controller.php 你可以当做一个控制器,因为它实现了主要的业务逻辑(虽然极其简单)。尽管简洁,但在结构上我们已经完全分离。
事实上,目前所有的框架的视图的实现都大致如此,没什么特别的、神秘的地方,只是说框架它做了更多的事,比如验证视图文件的合法性、通过更少的参数去加载视图等等。
如何传递一个变量到视图文件?
我相信很多人在这个上面有着很多的疑惑。比如我们常看到这样向视图传递变量:
// laravel 通过视图类的 with 方法传递
View::make('view')->with('value', '实际的数据'); // Smarty 模板引擎通过 assign 方法向最终的编译好的视图传递变量
$smarty->assign('value', '实际的数据'); // ...
实际上,在上面的逻辑与视图分离的例子中已经说了。当 include 或 require 一个文件时,该文件会继承引入他的那段代码的作用域。php 官方文档是这么说的:
当一个文件被包含时,其中所包含的代码继承了 include 所在行的变量范围。从该处开始,调用文件在该行处可用的任何变量在被调用的文件中也都可用。不过所有在包含文件中定义的函数和类都具有全局作用域。
如果 include 出现于调用文件中的一个函数里,则被调用的文件中所包含的所有代码将表现得如同它们是在该函数内部定义的一样。所以它将遵循该函数的变量范围。此规则的一个例外是魔术常量,它们是在发生包含之前就已被解析器处理的。
实战 —— 实现一个视图类
假设我们有一个视图类,定义在文件 View.php:
<?php
class View
{
protected $data = []; public function display($file)
{
extract($this->data); include $file;
} public function assign($key, $value)
{
$this->data[$key] = $value;
}
}
我们现在有模板文件,定义在文件 Template.php:
<!DOCTYPE html>
<html>
<head>
<title><?=$title?></title>
<meta charset="utf-8">
</head>
<body>
<h1><?=$title?></h1>
<p>
<?=$content?>
</p>
</body>
</html>
然后我们的主要业务逻辑代码如下:
<?php
// 包含视图类文件
include 'View.php'; $view = new View(); $view->assign('title', '视图测试');
$view->assign('content', '这是一个视图类的示例'); $view->display('Template.php');
输出的内容大家都已经看得出来了,我就不截图了。
至此,大家应该都明白如何实现一个视图了吧?其实原理就这么简单。
模板引擎
模板引擎的诞生实际上是将视图拆分出来以后的事儿。大家看到了,上面例子中,所有模板中的变量,都是通过原生的 php 语法进行输出。假如单纯是输出内容,其实不用模板引擎也可以,但是一旦涉及到需要复用模板或者对视图文件进行模块化的拆分,实现诸如继承、布局之类的功能时,原生的 php 语法似乎需要写更为复杂的代码才能实现。
很显然,我们不应该在视图文件内写超出职责或过于繁杂的额外代码,因此,模板引擎就显得十分必要。
模板引擎的用处并不是所谓的方便前端的美工和网页设计师,因为原生的语法比很多模板引擎语法更为简洁。实际上,模板引擎最主要的任务是简化在视图上的额外代码,比如处理布局、模板继承等等。
说了那么多,如何实现模板引擎?
其实模板引擎就是将一个指定的模板标记通过正则匹配,替换成相应的合法 php 语句而已。
转:https://www.insp.top/article/use-php-to-achieve-view-component-and-template-engine
用 php 实现一个视图组件和模板引擎——基础的更多相关文章
- 写一个迷你版Smarty模板引擎,对认识模板引擎原理非常好(附代码)
前些时间在看创智博客韩顺平的Smarty模板引擎教程,再结合自己跟李炎恢第二季开发中CMS系统写的tpl模板引擎.今天就写一个迷你版的Smarty引擎,虽然说我并没有深入分析过Smarty的源码,但是 ...
- SpringBoot 之 视图解析与模板引擎、 热部署、日志配置(四)
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 一 . SpringBoot环境下的视图解析技术 1. JSP JSP 是我们常用的视图技术了,但是Sp ...
- Laravel 5.2 三、中间件、视图与 Blade 模板引擎
一.中间件 Laravel 的 HTTP 中间件提供了对路由的一层过滤和保护.下面模拟一下用中间件验证后台登录. 1. 创建中间件 cmd 窗口进入项目目录,使用 artisan 命令创建 php a ...
- Laravel之视图和Blade模板引擎
一.视图 1.视图文件存放在resources/views目录2.视图载入及传参 return view('greeting', ['name' => 'James']); 还可以通过with ...
- 一个简单的PHP模板引擎
PHP早期开发中通常是PHP代码和HTML代码混写,这也使代码中充斥着数据库操作,逻辑处理等.当项目不大时,这样的代码还可以接受,但是随着项目不断扩大,我们就会发现同一个文件中同时存在前端逻辑和后端处 ...
- thymeleaf模板引擎基础使用(转)
刚好项目上用到这个模板引擎,记录以下基础用法. thymeleaf介绍 简单说, Thymeleaf是一个跟Velocity.FreeMarker类似的模板引擎,它可以完全替代JSP .相比其他的模板 ...
- smarty模板引擎基础(二)
smarty模板引擎所需文件夹共可分为存放页面缓存的(cache).存放配置文件的(configs).存放模板扩充插件的(plugins).存放模板文件的(templates).存放编译后的模板文件的 ...
- 一个JavaScript组件都需要哪些基础api
{ init: function() { // 模块初始化,包括属性初始化和配置初始化及调用父类的初始化方法 } ,build: function() { // 模块构建,包括子模块构建,dom构建, ...
- thymeleaf模板引擎基础知识
一.表达式 分为四类: 1.变量表达式 ${} :获取容器上下文变量的值. 举例: 获取application域中的username: ${application.username} 获取sessio ...
随机推荐
- Dell最近的几款显示器看上去还不错的样子
发现最近戴尔最近发布了两款的4k显示器P2415Q和P2715Q,价格还比较平易近人,淘宝价24寸3700,27寸4700,让人有点心动了.基本参数如下: 3840*2160分辨率 亮度350cd/m ...
- QJSON封装好的序列和还原方法
QJSON封装好的序列和还原方法 {*******************************************************}{ }{ QJSON与数据集互转 }{ }{ 版权所 ...
- 【java】java获取对象属性类型、属性名称、属性值
java获取对象属性类型.属性名称.属性值 获取属性 修饰符:[在Field[]循环中使用] String modifier = Modifier.toString(fields[i].getModi ...
- JavaMail入门:创建纯文本、HTML格式的邮件
转自:http://haolloyin.blog.51cto.com/1177454/353849/ 在 http://java.sun.com/products/javamail/ 下载了 Java ...
- SpringMVC中拦截器的使用
什么是拦截器 拦截器通常一般指的是通过拦截从浏览器发往服务器的一些请求来完成某些功能的一段程序代码一般在一个请求发生之前,发生时,发生后我们都可以对请求进行拦截 拦截器可以做什么 拦截器可以用于权限验 ...
- jquery load 方法回显数据
使用jQuery对象.load()方法 load() 方法的作用是可以通过 AJAX 请求从服务器加载数据,并把返回的数据直接放置到指定的元素中. 该方法使用起来非常简单,大大简化了ajax开发 语法 ...
- 通过命名管道协议方式访问群集SQL的一个小问题
原来的单机实例SQL如果开放命名管道协议访问可以在.Net程序的连接字符串中增加“;Net=dbnmpntw"以通过命名管道协议方式访问,但是当迁移到群集SQL后,.net通过它可能无法正常 ...
- IOS开发错误
After modifying system headers, please delete the module cache at '/Users/XXX/Library/Developer/Xcod ...
- SQL Server 获取某时间点后修改的函数Function 并以文本格式显示
修改查询分析器如下选项 右键=>查询选项 =>结果=>文本=> 取消 在结果集中包括列标题 的勾选 右键=>将结果保存到=> 选择 以文本格式显示结果 执行如下SQ ...
- Delphi控件开发浅入深出(三)
三.开关控件TlincoSwitch 用过Delphi1(好古老的东东呀!)的人相信都记得这个开关控件 ,不知道当初Borland为什么把这么一个在开发普通应用程序中应用不到的工控控件放到Delphi ...