自己幻想的模板解析方式【求拍砖】

kyzy_yy_pm 2012-05-29 05:11:07
加精
好久不来CSDN,感觉有点跟不上时代的潮流了,所以飞快的看了下推荐帖子,看见了许大大的模板引擎,所以一时心痒痒也练了下手(本人还是头一次弄这东西),只实现了if、foreach的解析,当然了,其中有很多死角,而且我感觉我写的这个很怪异,希望大家帮忙梳理下,本人喜欢被拍



class Template
{
public $template_dir = null; // 模板目录
public $compile_dir = null; // 编译目录
public $cache_dir = null; // 缓存目录
public $cache_life = 0; // 缓存时间
public $force_compile = false; // 是否强制编译
public $left_delimiter = '{'; // 左边界符
public $right_delimiter = '}'; // 右边界符

public $var_list = array(); // 变量集合
public $tpl_name = null;

/**
* 编译并显示模板
*
* @param string|array $var 变量名|变量数组
* @param all 变量值
*/
public function assign($var, $value = null)
{
if (is_array($var)) {
$this->_assign_arr($var);
} else {
$this->_assign_var($var, $value);
}
}

/**
* 编译并显示模板
*
* @param string $string
*/
public function display($tpl_name)
{
$this->template_dir = rtrim($this->template_dir, '/');
$tpl = $this->template_dir . '/' . $tpl_name;

if (is_file($tpl)) {
$this->tpl_name = $tpl_name;
$this->fetch(file_get_contents($tpl), true);
} else {
throw new Exception("Template \"{$tpl_name}\" does not exist");
}
}

/**
* 编译字符串
*
* @param string $content
* @param bool $print 是否输出(true-输出)
* @param bool $print_exit 输出终止
* @return echo|string
*/
public function fetch($content, $print = false, $print_exit = true)
{
$contents = false;
if ($this->cacheing) {
$contents = $this->_get_cache();
}
if ($contents === false) {
$compile_file_path = $this->_compile($content);
extract($this->var_list);

ob_start();
require_once($compile_file_path);
$content = ob_get_contents();
ob_end_clean();

if ($this->cacheing) {
$this->_set_cache($content);
}
} else {
$content = $contents;
}

if ($print) {
echo $content;
if ($print_exit) exit;
} else {
return $content;
}
}

/**
* 设置缓存
*
* @param string $content
* @return string
*/
private function _set_cache($content)
{
$cache_file = $this->tpl_name;
$cache_file_path = $this->cache_dir . '/' . $cache_file;
$this->_mkdir('cache_dir', '0777', true);
@file_put_contents($cache_file_path, $content . "<!--{/**{$this->cache_life}**/}-->");
}

/**
* 获取缓存
*
* @return bool/string
*/
private function _get_cache()
{
$cache_file = $this->tpl_name;
$cache_file_path = $this->cache_dir . '/' . $cache_file;
if (is_file($cache_file_path)) {
$contents = file_get_contents($cache_file_path);
$cache_life_match = preg_match('#<\!--{\/\*\*(\d+)\*\*\/}-->#', $contents, $arr);
if (!$cache_life_match) {
return false;
}
$cache_life = $arr[1];
$filemtime = filemtime($cache_file_path);
if ($filemtime + $cache_life > time()) {
return file_get_contents($cache_file_path);
} else {
return false;
}
}
return false;
}

/**
* 编译
*
* @param string $content
* @return string
*/
private function _compile($content)
{
$content = $this->_match($content);
$compile_file = md5_file($this->template_dir . '/' . $this->tpl_name) . $this->tpl_name . '.php';
$compile_file_path = $this->compile_dir . '/' . $compile_file;

if ($this->force_compile || !is_file($compile_file_path)) {

// 删除原编译文件
$unlink_file = '*' . $this->tpl_name . '.php';
if (strpos(strtolower(PHP_OS), 'win') === false) {
$cmd = "rm -f compile_dir/{$unlink_file}";
} else {
$cmd = "del compile_dir\\{$unlink_file}";
}
exec($cmd);

$this->_mkdir('compile_dir', '0777', true);
@file_put_contents($compile_file_path, $content);
}

return $compile_file_path;
}

/**
* 匹配
*
* @param string $content
* @return string
*/
private function _match($content)
{
// if
$replace = array(
'#' . $this->left_delimiter . 'if[ ]+([^' . $this->right_delimiter . ']+)' . $this->right_delimiter . '#is' => '<?php if (\1) {?>',
'#' . $this->left_delimiter . '/if' . $this->right_delimiter . '#is' => '<?php }?>',
);
$content = preg_replace(array_keys($replace), array_values($replace), $content);

// foreach
$replace = array(
'#' . $this->left_delimiter . 'foreach[ ]+from=\$([a-z_]+\w*)[ ]+item=([a-z_]+\w*)[ ]*' . $this->right_delimiter . '#is' => '<?php foreach ($\1 as $\2) {?>',
'#' . $this->left_delimiter . '/foreach' . $this->right_delimiter . '#is' => '<?php }?>'
);
$content = preg_replace(array_keys($replace), array_values($replace), $content);

// variables
$content = preg_replace_callback('#' . $this->left_delimiter . '(((?!\?>).)*(\$(\.?\w+)+)[^' . $this->right_delimiter . ']*)' . $this->right_delimiter . '#i', array($this, '_back'), $content);

return $content;
}

private function _back($m)
{
$s = $m[1];
$r = '#\$(\.?\w+)+#i';
preg_match_all($r, $m[1], $list);
foreach ($list[0] as $val) {
$arr = explode('.', $val);
$var = '';
foreach($arr as $v) {
if (strpos($v, '$') === false) {
$var .= '[\'' . $v . '\']';
} else {
$var .= $v;
}
}
$s = strtr($s, array($val => $var));
}
return '<?php echo ' . $s . ';?>';
}

/**
* 创建内部目录
*
* @param string $type 创建类型(compile_dir-编译目录|cache_dir-缓存目录)
* @param string $mode 权限
* @param bool $recursive 是否递归创建
* @return bool
*/
private function _mkdir($type, $mode = '0777', $recursive = false)
{
$allow_type = array('compile_dir', 'cache_dir');
if (!in_array($type, $allow_type)) {
throw new Exception("Not allowed to create the type of \"{$type}\".");
}

$dir = null;
switch ($type) {
case 'compile_dir':
$dir = $this->compile_dir;
break;
case 'cache_dir':
$dir = $this->cache_dir;
break;
}

if (!$dir) {
throw new Exception("Please specify the \"{$type}\" directory.");
}
if (!is_dir($dir) && !mkdir($dir, $mode, $recursive)) {
throw new Exception("\"{$dir}\" Failed to create \"{$type}\" directory");
}
return true;
}

/**
* 检测变量名是否和服
*
* @param string $var 变量名
* @return bool
*/
private function _check_var($var)
{
$var_rule = '#^[a-z_]+\w*$#i';
if (preg_match($var_rule, $var)) {
return true;
}
return false;
}

/**
* 单变量赋值
*/
private function _assign_var($var, $value)
{
if ($this->_check_var($var)) {
$this->var_list[$var] = $value;
}
}

/**
* 多变量赋值
*/
private function _assign_arr($data)
{
foreach ($data as $var => $value) {
if ($this->_check_var($var)) {
$this->var_list[$var] = $value;
}
}
}
}

$t = new Template;

$t->template_dir = 'template';
$t->compile_dir = 'compile_dir';
$t->cache_dir = 'cache_dir';
$t->cacheing = false;
$t->cache_life = 5;
$t->force_compile = true;
$t->left_delimiter = '{';
$t->right_delimiter = '}';

$c = array(
'user1' => array('username' => 'zhangsan', 'age' => 20),
'user2' => array('username' => 'thelisis', 'age' => 22)
);
$t->assign(array('a' => 123, 'b' => 'abc', 'c' => $c, 'x' => true));
$t->display('t.html');

...全文
2785 70 打赏 收藏 转发到动态 举报
写回复
用AI写文章
70 条回复
切换为时间正序
请发表友善的回复…
发表回复
卡夫卡的小丫 2012-06-09
  • 打赏
  • 举报
回复
很多地方不完善,一般般,你还要努力啊。。
xjb985462426 2012-06-09
  • 打赏
  • 举报
回复
受教了。。。
cwh123150 2012-06-08
  • 打赏
  • 举报
回复
这个不会诶
wuhanys 2012-06-06
  • 打赏
  • 举报
回复
求HG526 备份文件加密解密工具
mordan 2012-06-06
  • 打赏
  • 举报
回复
不懂为什么要用模板引擎,难道是怕有些程序员把不该写在v的代码写在v上
Anew_G 2012-06-05
  • 打赏
  • 举报
回复
先Mark 对模板引擎本身的概念还基本没搞懂
wushuang443 2012-06-05
  • 打赏
  • 举报
回复
顶一个。。支持下
mklyl 2012-06-04
  • 打赏
  • 举报
回复
厉害,看不懂。
z314791356 2012-06-04
  • 打赏
  • 举报
回复
厉害,看不懂。
zhoujun195301 2012-06-03
  • 打赏
  • 举报
回复
参考一下!
xuzuning 2012-06-01
  • 打赏
  • 举报
回复
to #47
要求变量名唯一,虽然无可厚非。php 不也是这样的吗?

好在你没有考虑在模板里嵌入模板。不然的话,这个不可重名可是要大伤脑筋了
jim5589840 2012-06-01
  • 打赏
  • 举报
回复
不错嘛呵呵呵
kyzy_yy_pm 2012-06-01
  • 打赏
  • 举报
回复
[Quote=引用 42 楼 的回复:]

assign赋值有问题吧 会被覆盖的
[/Quote]

[Quote=引用 43 楼 的回复:]

assign赋值有问题吧 会被覆盖的
[/Quote]

算上你们两位已经是好几为提出这个问题了,不过我认为这个是合理的,因为在smarty中assign的赋值方式有两种,第一种是单个变量赋值,第二种是数组方式(多变量)赋值,那么这样来看应该是单变量赋值中的变量名和多变量赋值中的数组元素的变量名(key)是同一级关系,呵呵,这是我的理解,不知道大家说的覆盖是不是这块
kyzy_yy_pm 2012-06-01
  • 打赏
  • 举报
回复
[Quote=引用 39 楼 的回复:]

感觉没撒用,换汤不换药,如果有可能,我倒是希望看看唠叨哥的模板,难道大家就没有兴趣吗?
[/Quote]

已经写过了,在推荐里面呢
YANCHANGJI 2012-06-01
  • 打赏
  • 举报
回复
来看看,学学
zkyEric 2012-06-01
  • 打赏
  • 举报
回复
支持楼主~~,学习。
zzzsylxl1 2012-06-01
  • 打赏
  • 举报
回复
虽然看不懂 还是来看看。
代码如诗 2012-05-31
  • 打赏
  • 举报
回复
[Quote=引用 35 楼 的回复:]

引用 33 楼 的回复:

to #32
你的思路与楼主的完全不一样,你是直接将数据替换进模板里
而楼主是要将模板处理成混合编码的php程序

你的需要每一运行都进行替换
而楼主的只需处理一次,一次以后就可以直接运行生成的 php 代码了


很中肯的评价
[/Quote]既然知道评价中肯,就应该明白差距在哪里了吧,每次运行都进行替换,相当程度上降低了系统性能,这样的模板引擎还有什么优势??
狄默默斯基 2012-05-31
  • 打赏
  • 举报
回复
[Quote=引用 34 楼 的回复:]
的确是有差距的,我看了一下,按照你说的一年多了,你已经累计有5次下载,和1毛钱的运营盈利。跟他这个只是会发个帖子,贴些代码,又没人下载,又没盈利的情况,差距实在太大了。
[/Quote]

这跟程序没关系,是知名度的问题,没名气,再好的东西也不行啊,名气要宣传才有啊,宣传么肯定是一个浩大的工程项目哇,一个人叽喳叽喳谁理啊

你就别瞎搞了
狄默默斯基 2012-05-31
  • 打赏
  • 举报
回复
[Quote=引用 33 楼 的回复:]

to #32
你的思路与楼主的完全不一样,你是直接将数据替换进模板里
而楼主是要将模板处理成混合编码的php程序

你的需要每一运行都进行替换
而楼主的只需处理一次,一次以后就可以直接运行生成的 php 代码了
[/Quote]

很中肯的评价
加载更多回复(38)

21,886

社区成员

发帖
与我相关
我的任务
社区描述
从PHP安装配置,PHP入门,PHP基础到PHP应用
社区管理员
  • 基础编程社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧