`
石不易
  • 浏览: 8167 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

【PHP 模板引擎】Prototype 原型版发布!

阅读更多

在文章的开头,首先要向一直关注我的人说声抱歉!因为原本是打算在前端框架5.0发布之后,就立马完成 PHP 模板引擎的初版。但我没能做到,而且一直拖到了15年元旦才完成,有很严重的拖延症我很惭愧,再次抱歉!

之前有说过以后的作品发布文章都会同步发表相应的 API 使用说明,但我觉得这还不够好而且博客平台对表格的处理和显示不是很友好,导致 API 不能完美的呈现,因此打算只提供 API 链接,大家可以通过链接直接访问到我的官网去查阅手册,那样的阅读体验是最好的。而发布的文章以后则更新一些和 API 相关的使用教导,提供一些小例子,让大家在阅读 API 的同时,也能够通过实际例子去更加深刻的体会到代码的各种用法与业务逻辑思想!

 

 

以下是 API 手册与实例演示链接

 

【实例演示】http://www.shibuyi.net/demo/php/template_engine/prototype

【官方 API 使用手册】http://www.shibuyi.net/api/php/template_engine/prototype

【笔者个人官网】http://www.shibuyi.net

 

 

下面为 PHP 模板引擎 Prototype 原型版使用教导,以下直接简称:模板引擎!

 

什么?不知道模板引擎是啥?可能会有 PHP 新手会问这样的问题,那我就简单的回答一下吧。模板引擎其实就是 PHP 的一个中间件技术,让传统的 Web 动态网站编程变得更加轻松,为什么这么说呢?以前不轻松吗?那是因为在模板引擎出现之前,几乎所有的 Web 服务端程序员都是通过混编代码完成工作的,所谓混编就是一张页面中既包含:PHP 也包含 HTML 甚至还有其他语言的代码,因此项目如果逐渐扩展,开发和维护的时间成本是极高的,还容易出错,美工与程序也不好配合,如果美工一点也不理解程序,那基本上没办法看混编文件。而模板引擎的诞生就很好的解决了这一难题。它采用模板技术将混编文件中的 PHP 业务逻辑层代码与 HTML 表现层代码进行了很好的切割分离,程序员则可以安心的设计程序,而美工则安心的设计界面,二者之间会使用一种模板标记的特殊符号进行关联,方便模板引擎读取模板文件之后可以顺利的进行编译操作。市面上 PHP 已经有很多相当成熟的模板引擎了,如:Smarty 模板引擎等等,其他 Web 服务端语言也有自己相应的模板引擎,或者与模板引擎类似的中间件技术。

 

关于模板引擎的详细介绍,推荐大家访问百度百科:http://baike.baidu.com/view/4258079.htm

 

在学习模板引擎之前大家要先保证自己已经了解了 PHP 的 OOP(面向对象编程)思想,因为模板技术是采用 OOP 思想描述的,如果不懂 OOP 那么这篇文章就不适合您阅读,因为门槛过高!

 

首先大家看到的图片是模板引擎的目录结构图(笔者使用的是 ZendStudio 7.2.1 集成开发环境):

1. caches 为模板缓存目录(若不存在模板引擎第一次执行会自动生成);

2. classes 为模板引擎核心类库;

3. compiles 为模板编译目录(若不存在模板引擎第一次执行会自动生成);

4. constants 为模板常量目录(若不存在模板引擎第一次执行会自动生成);

5. includes 为模板配置目录;

6. templates 为模板文件目录(若不存在模板引擎第一次执行会自动生成)。

 

在了解了模板引擎的目录后,接下来我们就来看看如何让他运作起来。在原型版中模板引擎的相关初始化和配置信息都是在 includes/template.inc.php 文件中完成的(大家可以打开实例演示的源码进行查阅)。

 

其实对模板引擎的配置又叫做初始化的过程,初始化的第一步就是配置相应的目录,让模板引擎能够正确的读取和写入该目录中的数据(配置步骤大家可以自由选择,不一定非要按照我的顺序来配置,但一定要在实例化模板引擎之前完成,否则将会失效),而我们则假设与模板引擎在同一目录下进行配置,并且创建 index.php 文件用来存储配置信息,如果非同一目录对于根目录的配置则需要注意调整。

 

 

1. 首先第一步是配置模板引擎的根目录,如果不设置则会自动生成根目录的绝对路径。 

Template :: $rootPath = dirname(__FILE__); // 相对与绝对路径均可,我们这里则采用绝对路径!如:"C:/wwwroot/prototype"

 

2. 配置模板文件目录,这个目录是用来存放模板文件的,如果不设置则默认为:templates 目录。

// 这里则采用默认目录,大家根据自己的需求进行设置,建议不要写中文容易出错,目录名的前后加不加正反斜杠都无所谓,最终模板引擎内部会自动校正!
Template :: $templateName = '/templates/';

 

3. 配置编译文件目录,这是用来存储模板文件被解析后生成的编译文件,如果不设置则默认为:compiles 目录。

Template :: $compileName = '/compiles/'; // 和模板目录一样也采用默认目录。

 

4. 配置缓存文件目录,这是在模板引擎开启缓存功能后,用来存储编译文件生成的缓存文件,如果不设置默认为:caches 目录。

Template :: $cacheName = '/caches/'; // 一样使用默认

 

5. 配置模板常量目录,可能大家不太理解模板常量是用来干嘛的,和普通的 PHP 常量又有什么区别?关于模板常量的解释,在接下来的运用中我们在详细探讨,这里就先跟我进行配置即可,如果不设置则默认为:constants 目录。

Template :: $constantName = '/constants/'; // 使用默认

 

6. 到第六步为止,目录的配置就全部完成了,大家不用担心目录不存在的问题,也无需手动去创建,模板引擎内部会自动帮我们完成。那么接下来就是设置模板常量的文件名称,如果不设置则默认为:default.xml 文件,和目录一样不存在模板引擎会自动创建。

// 我们也采用默认,但大家要注意的是这里必须采用 .xml 为扩展名,因为常量文件是以 XML 标记描述的,如果不是 .xml 结尾,那么可能会导致模板引擎在处理常量时出现异常情况!
Template :: $constantFile = 'default.xml';

 

7. 设置缓存开关,缓存默认情况下是被关闭的,只有我们去设置他,才会开启。

// 大家注意,这里我写的是一个布尔值,其实这里可以填写任意值,最终都会被隐式转换为布尔值,写 0 或 1 都可以,我直接写布尔值是为了方便大家的理解!
Template :: $cacheSwitch = true;

 

8. 至此模板引擎的配置基本上就已经全部完成了,还是很简单的。现在我们只需要实例化出模板引擎对象,就可以真正的运行模板引擎了。

$tpl = new Template(); // 实例化出模板引擎,从这一步开始之前的所有配置全部生效,模板引擎实例化时不需要传递任何参数。

  

9. 在实例化出模板引擎对象以后,我们就可以开始对其进行操作,那么对谁进行操作呢?当然是模板文件了,首先我们要先创建模板文件。在模板文件目录中进行创建。模板文件其实是纯 HTML 代码文件,扩展名可以自定义,而我们约定俗成,都以 .tpl 为扩展名。假设我们已经创建了一个模板文件名为:index.tpl,因为和我们的 php 业务逻辑文件 index.php 同名,这也是按照惯例约定俗成,因为 index.php 文件调用 index.tpl 模板,见名知意。

 

10. 在创建了模板文件之后,我们就可以在业务文件(之前的配置也都是在 index.php 中执行的)中进行对模板文件的加载以及注入模板变量,关于模板变量和其他的模板标识符(又统称模板标记)将在接下来的步骤中逐一讲解。

// 注入变量的格式有两种,大家注意看 API 手册的说明,数组格式与传统的键值对格式均可以,我们两种都使用一下。
$tpl -> assign('title', '头衔'); // 首先是传统键值对格式

$tpl -> assign(array('title' => '头衔', 'name' => '名称')); // 数组格式明显要更加好用一些,因为在注入多个变量时,就可以不用写多个注入语句,一句话就搞定了。

// 如果出现了两个一模一样的变量名称,那么其后会将之前的给替换掉。以下代码,最终 language 变量的值为:英文。
$tpl -> assign(array('language' => '中文', 'language' => '英文'));

// 接下来是加载模板文件,直接写模板名称即可,模板引擎会自动锁定到模板文件目录。
$tpl -> display('index.tpl');

 

11. 至此对模板引擎的操作就结束了,接下来我们将熟悉一下模板文件中的各个模板标记的使用方法,他们都是用来做什么的。在原型版中模板标记一共有 9 种,分别为:1. 模板变量、2. 模板常量、3. 单行模板注释、4. 多行模板注释、5. include 文件加载、6. template 模板文件加载、7. source 源模板文件加载(较为特殊)、8. if 分歧语句、9. foreach 循环语句。那么我们首先解释一下模板变量吧。

<div id="main">
    <!-- 刚刚我们注入了 title 变量,那么在模板文件中就可以对其进行调用了,调用方法就是保持同名,按照这样的格式抒写即可{$模板变量名称}-->
    <!-- 模板变量的命名规范与 PHP 普通变量一模一样,首位不能为数字,且区分大小写,注意保证格式的正确性,如果错误模板引擎将不会对其进行解析 -->
    <a href="###">{$title}</a> <!-- 正确的格式,被正确解析 -->
    <a href="###">{$123}</a> <!-- 错误的格式,无法解析 -->
</div>

 

12. 下面是模板常量的使用,模板常量和 PHP 常量虽然名字上都叫他常量,其实本质上并非一回事。模板常量其实可以看做是伪常量,而并非真正的常量,他是通过对 XML 标记的存储,来实现一种全局不变的特定值,这些值需要手动的添加到常量文件中。(手动添加其实不太方便,笔者会在其后的版本迭代中,加入自动添加的功能)

首先我们需要在模板常量文件中手动添加模板常量,代码如下:

<?xml version="1.0" coding="utf-8" ?>
<root>
    <!-- 必须在 root 根标记中间进行添加,而且一个标记字母都不能出错,注意区分大小写,如果不慎写错,模板引擎将无法对其进行获取 -->
    <constant>
        <key>WEBNAME</key> <!-- 这里填写常量名称注意字母必须全部大写,第一位不能为数字,格式与 PHP 定义常量一样 -->
        <value>网站标题</value> <!-- 常量值 -->
    </constant>
    
    <constant>
        <key>123abc</key> <!-- 错误的常量名 -->
        <value></value> <!-- 值可以为空 -->
    </constant>
</root>

 

配置好常量后,接下来就是在模板文件中进行调用,代码如下:

<!-- 模板常量的调用和变量类似,只是取消了 $ 符号,另外和配置的常量名要保持一致 -->
<title>{WEBANME}</title> <!-- 正确的名称,将被正确解析 -->
<p>{NAME}</p> <!-- 虽然格式正确,但刚才没有进行 NAME 常量的配置,因此最终解析后会返回一个空值 -->
<p>{abc123}</p> <!-- 错误的名称,无法解析 -->

 

13. 下面是模板的注释符,有两种:一种为单行,一种为多行。常用于对模板文件代码的注解,可以让美工配合设计界面的时候了解代码的实际含义。

<!-- 大家可以把模板注释放到 HTML 注释符号中,这样美工在设计模板页面的时候会更加一目了然。-->
<!-- 单行注释的格式是:{@}内容可写可不写,但不写也就没有意义了 -->
{@ 普通的单行注释} <!-- 正确的格式 -->
<!-- {@ HTML 注释符号中的单行注释} --> <!-- 正确的格式 -->
{@ 换行的
单行注释} <!-- 格式错误,单行注释无法换行,模板引擎无法解析 -->

<!-- 多行注释的格式是:{#}...{/#}一头一尾要呼应,内容也可以不写 -->
{#}这是多行注释,注意首位呼应!{/#} <!-- 正确的格式 -->
{#}这是多行注释,
我换行了!{/#} <!-- 正确的格式 -->
{#} 没有写结尾符号 <!-- 错误的格式,模板引擎无法解析 -->

 

14. 模板加载标识符,加载方式分为 3 类,别分为:include 对普通文件的直接加载;template 对模板文件进行编译后加载;source 对模板文件进行编译后直接输出编译文件的路径(此方法较为特殊且并不完美,需要在特定的场合中使用,比如:框架页面的调用)

首先是对普通文件的加载调用,代码如下:

<!-- 注意抒写格式,被直接加载的文件多半是 php 文件,且文件必须要存在,不存在的文件,模板引擎将会给出一个错误提示,并且终止代码的执行 -->
<!-- 文件名前后的引号,单双引号都可以,但必须保持一致,不能一单一双,否则模板引擎将不会对其解析 -->
{include path = "test.php"} <!-- 正确的格式,将被解析 -->
{include path = 'abc.php"} <!-- 错误的格式,无法被解析 -->
<!-- 如果出现了同一个文件被加载了两次,那么模板引擎只会对其加载第一次后,自动忽略其后的加载 -->
{include path = "123.php"} <!-- 第一次被加载成功 -->
{include path = "123.php"} <!-- 与上一个文件同属一个文件,将无法被再次加载,而被自动忽略 -->

 

下面是对模板文件的编译加载,代码如下:

<!-- 格式与 include 方式基本一样,就不重复阐述了,不一样的是 include 是需要给出具体的路径地址,而 template 则只需要给出模板名称即可,模板引擎会自动找到该模板文件 -->
{template path = 'test.tpl'} <!-- 正确的格式,将会被编译后加载 -->

 

最后就是模板文件的编译地址的输出,该功能较特殊,即使不理解也没关系,该方法有严重的 BUG 尚未处理完毕,因此并不完美,且使用的概率也极低,这里只做简单的介绍。在其后的版本迭代中,是否会保留并完善,尚在定夺,代码如下:

<!-- 这里我们将使用 iframe 框架页面,来调用 source 加载方法,调用格式与前两种雷同,就不在阐述 -->
<!-- 这样使用其实就可以了,但有严重的 BUG 出现,原因是所有在 frame.tpl 中注入的模板标记被解析后,将无法找到源头,也就是说 php 将无法对其正确处理,并且因为无法找到源头,而会报错,该 BUG 的解决方案还在研究中,这里仅提供给大家思考 -->
<iframe src="{source path = 'frame.tpl'}"></iframe>

 

15. 接下来是经常会被用到的 if 分歧语句,他和 php 的 if 语句很类似,但功能上却很简单,且不支持多重判断以及嵌套判断,但我会在其后的版本迭代中让其功能逐步强大。

<!-- if 语句的格式其实和多行注释一样,一定要注意首位呼应,但大小写无所谓都能够支持和 PHP 原生的 if 语句是一样的。 -->
{if $action} <!-- 只要被注入的 {$action} 变量的值为 true,或隐式转换后为 true,那么 if 语句中的代码将被显示 -->
<p>界面1</p>
{/if}

{if !$action} <!-- 加入了逻辑非的判断,只要为 false 则被显示 -->
<p>界面2</p>
{/if}

{if $action} <!-- 双层判断的时候,为 true 时显示界面1,为 false 时显示界面2 -->
<p>界面1</p>
{else}
<p>界面2</p>
{/if}

{if $action} <!-- 错误的格式,没有结尾,不会被模板引擎解析 -->

 

16. 终于到了最后的也是最复杂的 foreach 循环语句的调用了,其功能和 PHP 一样,只是格式上稍有改动。

<!-- 注意在调用 foreach 和 if 语句一样要首尾呼应,而且如果变量不是数组格式,那么 php 将会自动报出一个错误 -->
<!-- 其中 $array 就是被注入的模板变量,注意要是数组格式;而 key 和 value 则是对应数组中的键值对,必须写,否则格式不正确,将无法被模板引擎解析 -->
{foreach $array(key, value)}
    <p>{%key} ... {%value}</p> <!-- 注意键值对可以不是 key 和 value,但一定要和之前同名,否则无法被解析 -->
{/foreach}

{foreach $userList(id, username)}
<p>{%id} ... {%username}</p> <!-- 自定义的 key 和 value,格式正确 -->
<p>{%password}</p> <!-- 错误的格式,并没有被定义,因此无法被解析 -->
{/foreach}

 

好了,写到这里我也可以长长的舒口气,模板引擎原型版的教导到此就结束了。虽然教导文章已经很详细了,但建议大家配合 API 手册和实例代码进行参照阅读,这样效果会更好更便于理解和掌握。当然因为是文章,所以即使你描述的再详细,文字也是抽象的,需要大家多动手,而对于动手能力较差的新手们,这篇教导文章则起不到多大的作用,可能反而会被弄得一头雾水,甚至最终对此厌恶,所以我有想过如果以后有可能,在版本迭代更新到一定程度后,我会针对性的出一套系列教导视频,那样的话就不会像文字这样抽象,新手也能够很快的学习。

 

如果你是从头看到尾,那么我真心感谢您的阅览,我想你应该有什么话想说,请一定要在下面留言告诉我,有问题也请及时留言,感谢各位的支持~!

 

 

1
1
分享到:
评论
3 楼 月影无痕 2015-01-07  
石不易 写道
月影无痕 写道
这个看看就算了,我还是直接用原生态吧。
说实话,PHP中用类似的模板引擎,简直就是歧途。

呵呵,有意思的回复,为什么说用模板引擎是歧途呢~


从以下几个方面的对比:
性能
易用性
灵活性
学习成本

哪一个有优势?

与其让美工学习这个模板语法,不如学PHP语法呢?
2 楼 石不易 2015-01-07  
月影无痕 写道
这个看看就算了,我还是直接用原生态吧。
说实话,PHP中用类似的模板引擎,简直就是歧途。

呵呵,有意思的回复,为什么说用模板引擎是歧途呢~
1 楼 月影无痕 2015-01-07  
这个看看就算了,我还是直接用原生态吧。
说实话,PHP中用类似的模板引擎,简直就是歧途。

相关推荐

    原型设计模式prototype

    **原型设计模式(Prototype Pattern)**是一种创建型设计模式,它允许我们通过复制现有的对象来创建新对象,而不是通过构造函数来实例化新对象。在面向对象编程中,当我们需要频繁地创建具有相同或相似属性的对象时,...

    Prototype Pattern原型模式

    **原型模式(Prototype Pattern)**是一种基于克隆的创建型设计模式,它的主要目的是为了提高创建新对象的效率,特别是当创建新对象的过程复杂或者资源消耗较大时。在原型模式中,一个已经创建的对象(称为原型)被...

    网页模板——Prototype 开发者手册 PDF版.zip

    综上所述,"网页模板——Prototype 开发者手册 PDF版"是一个对前端开发者极其宝贵的资源,它不仅涵盖了Prototype的各个方面,还可能包含实践案例和调试技巧,对于提升开发者在JavaScript和前端开发领域的技能...

    javascript prototype原型操作笔记.docx

    ### JavaScript Prototype原型操作知识点 #### 一、Prototype基础概念 **Prototype** 在 JavaScript 中是一个非常重要的概念,它支持面向对象编程中的继承特性。每个 JavaScript 对象都有一个内部属性 `[...

    不是原型继承那么简单!!prototype的深度探索

    **原型(Prototype)**:是一种用于创建新对象的基础模板。当一个对象没有定义某个属性或方法时,JavaScript 引擎会沿着原型链向上查找,直到找到相应的属性或方法为止。 在 JavaScript 中,类(Class)和对象实例...

    JavaScript中的prototype原型学习指南

    Function 类型有一个属性 prototype,直接翻译过来就是原型。这个属性就是一个指针,指向一个对象,这个对象包含一些属性和方法,这些属性和方法会被当前函数生成的所有实例(对象)所共享。 这句话根据前面所说的,...

    Prototype-1.6.0 中文版\英文版\Prototype.js

    1. **类与对象继承**:Prototype.js引入了基于原型的类系统,允许开发者创建类并实现继承。这使得JavaScript代码可以采用面向对象的方式编写,增强了代码的可读性和可维护性。 2. **DOM操作**:Prototype提供了强大...

    prototype 原型

    prototype 原型,封装了好多方法,带有简单注释说明,一看就明白

    prototype原型模式

    - `prototype.cpp` 可能包含原型接口的实现,定义了复制对象的基本操作。 - `mainwindow.cpp` 和 `mainwindow.h` 可能是图形用户界面(GUI)的一部分,可能包含使用原型模式的界面组件。 - `prototype.h` 是原型接口...

    Prototype各版本

    Prototype 提供了类(Class)、原型继承(Prototype Inheritance)、事件处理(Event Handling)、元素操作(Element Manipulation)等核心特性,简化了 JavaScript 的开发工作。它还包括对 AJAX(异步 JavaScript ...

    PHP+AJAX+PROTOTYPE国省市三级联动菜单原型

    在IT领域,尤其是在Web开发中,"PHP+AJAX+PROTOTYPE国省市三级联动菜单原型"是一个常见的功能实现,主要用于创建交互性强、用户体验良好的表单元素。这个原型设计旨在通过AJAX技术动态地从服务器端的PHP脚本获取数据...

    Java设计模式之Prototype原型模式

    Java设计模式之Prototype原型模式 Prototype原型模式是Java设计模式中的一种创建型模式,它主要用于对象的克隆和创建。该模式的主要思想是将一个对象作为原型,然后通过克隆该对象来创建新的对象,从而实现对象的...

    Prototype模式

    **原型模式(Prototype Pattern)**是一种创建型设计模式,它提供了一种通过复制已有对象来创建新对象的方式,而不是通过构造函数。在某些情况下,当创建新对象的成本非常高时(例如,对象需要大量的初始化操作或者从...

    设计模式之Prototype(原型)

    "原型"(Prototype)设计模式是其中的一种,它的主要目标是通过复制现有的对象来创建新的对象,而不是通过构造函数来创建新实例。这种方法尤其适用于当创建新对象的过程复杂或者昂贵时,例如,当对象需要大量初始化...

    设计模式 创建型模式 Prototype模式(原型)

    Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。...

    原型模式prototype

    **原型模式(Prototype)**是软件设计模式中的一种,它属于创建型模式,主要用于简化对象的创建过程,通过复制已有对象来生成新对象,避免了重复的构造过程,提高了代码的效率和可维护性。在Java、C#等面向对象语言...

    原型模式(Prototype)

    **原型模式(Prototype)** 原型模式是一种创建型设计模式,它提供了一种通过复制已有对象来创建新对象的方式,而不是通过传统的构造函数。这种模式在系统中需要创建大量相似对象时特别有用,可以提高效率并减少内存...

    C#面向对象设计模式纵横谈(6):Prototype 原型模式(创建型模式)

    6. **适用场景**:原型模式常用于需要频繁创建相似对象的情况,如游戏中的角色复制、文档编辑中的模板应用等。此外,它也可以作为工厂模式的一种补充,提供更灵活的对象创建方式。 总的来说,原型模式在C#中提供了...

    prototype_1.7.3.js 最新版本

    《prototype_1.7.3.js:JavaScript框架的里程碑》 在JavaScript的世界里,Prototype库是一个不可或缺的重要组成部分,尤其在Web开发领域,它为开发者提供了强大的功能和便利性。Prototype_1.7.3.js是这个库的一个...

    JavaScript中的prototype(原型)属性研究

    在JavaScript中,每个函数都有一个prototype属性,这个属性指向一个对象,这个对象就是所谓的原型对象。当我们创建一个函数实例时,实例会自动获取一个内部属性[[Prototype]],这个属性通常通过`__proto__`或者`...

Global site tag (gtag.js) - Google Analytics