别不多说,直接上代码
<?phpclass template { protected $data = array(); protected $drillmode = 0; function __construct($s) { if(file_exists($s)) $s = file_get_contents($s); $this->find_var($s); $this->data = explode('<', $s); $this->data[0] = '<?php $_st=$_var=array();?>'; $this->find_dsn(); } //新增 run 方法, function run() { //include "data://," . join('<', $this->data); eval('?>' . join('<', $this->data)); } function find($pattern) { $this->pattern = $pattern; return array_filter($this->data, array($this, 'find_callback')); } private function find_dsn() { foreach($this->find("#\bdsn\b#i") as $k=>$v) { $t = $this->find_tag($tag = strtok($v, ' '), $k); end($t); $dsn[] = array( $k, key($t) ); } if($this->drillmode) { foreach($this->find("#\bdrill\b#i") as $k=>$t) { foreach($dsn as $i=>$v) if($k < $v[1] && $k > $v[0]) $t = $i; $drill[] = $dsn[$t]; unset($dsn[$t]); } } foreach($dsn as $v) { list($start, $end) = $v; preg_match('/\bdsn\s*=\s*([^\s>]+)/i', $this->data[$start], $reg); $this->data[$start] = str_replace(' '.$reg[0], '', $this->data[$start]); $m = explode(',', trim($reg[1], '\'"')) + array(0, 0, ''); $code_start = "?php if(isset(\$_var))\$_st[]=\$_var;foreach((isset(\$_var['$m[0]'])?\$_var['$m[0]']:\$this->$m[0]('$m[1]','$m[2]')) as \$_key=>\$_var){?>"; $code_end = "?php }\$_var=array_pop(\$_st);?>"; switch($m[1]) { case 0: $t = explode('>', $this->data[$start]); $t[1] = "<$code_start" . $t[1]; $this->data[$start] = join('>', $t); $this->data[$end] = "$code_end<" . $this->data[$end]; break; case 1: $this->data[$end] .= "<$code_end"; $this->data[$start] = "$code_start<" . $this->data[$start]; break; default: $n = round(100/$m[1]); $this->data[$end] .= "</dt><$code_end"; $this->data[$start] = "$code_start<dt style='float:left;width:$n%;margin:0px;padding:0px'><" . $this->data[$start]; break; } } if($this->drillmode) foreach($drill as $v) { list($start, $end) = $v; preg_match('/\bdsn\s*=\s*([^\s>]+)/i', $this->data[$start], $reg); $this->data[$start] = str_replace(' '.$reg[0], '', $this->data[$start]); $m = explode(',', trim($reg[1], '\'"')) + array(0, 0, ''); $code = ''; for($i=$start; $i<=$end; $i++) { $code .= '<' . $this->data[$i]; if($i > $start) unset($this->data[$i]); } $code = addslashes($code); $this->data[$start] = "?php \$_code='$code';\$this->drill(\$_code, isset(\$_var['$m[0]'])?\$_var['$m[0]']:\$this->$m[0]('$m[1]','$m[2]'));?>"; } } protected function find_tag($tag, $offs=0) { $r = array(); $counter = 0; foreach($this->find("#^/?$tag#i") as $k=>$v) { if($k >= $offs) { $counter += $v{0} == '/' ? 1 : -1; $r[$k] = $v; if($counter == 0) break; } } return $r; } protected function find_callback($v) { return preg_match($this->pattern, $v); } private function find_var(&$s) { $s = preg_replace_callback('/\{(\w+)\}/', array($this, 'var_callback'), $s); } protected function var_callback($r) { if($r[1] == 'drill') { $this->drillmode++; return '<?php if(isset($_var[\'child\'])) $this->drill($_code, $_var[\'child\']);?>'; } return "<?php echo isset(\$_var['$r[1]'])?\$_var['$r[1]']:'';?>"; } protected function drill($_code, $_source) { if(empty($_source) || ! is_array($_source)) return array(); foreach($_source as $_key=>$_var) { //include 'data://,' . $_code; eval('?>' . $_code); } } function __call($func, $param) { if(function_exists($func)) return call_user_func_array($func, $param); return array(); } function __toString() { return join('<', $this->data); }}
{t}
1
2
12
测试例
include 'template.php';function body() { return array( array( 'title' => '布局', 'advertising' => '一贯喜欢用表格布局,这种 DIV+CSS 方式很让人头疼的', 'menu' => array( array('text' => '首页' ), array('text' => '博客' ), array('text' => '设计' ), array('text' => '相册' ), array('text' => '论坛' ), array('text' => '关于' ), ), 'footer' => '为什么表现不一样呢,IE就是对齐的', ), );}function img() { $ar['url'] = 'http://justinyoung.cnblogs.com/images/cnblogs_com/justinyoung/2007/tb_m.PNG'; return array($ar);}function tree() {$data = array( array('ID'=>1, 'PARENT'=>0, 'NAME'=>'祖父'), array('ID'=>2, 'PARENT'=>1, 'NAME'=>'父亲'), array('ID'=>3, 'PARENT'=>1, 'NAME'=>'叔伯'), array('ID'=>4, 'PARENT'=>2, 'NAME'=>'自己'), array('ID'=>5, 'PARENT'=>4, 'NAME'=>'儿子'),);$t = find_child($data, 'ID', 'PARENT');//print_r($t);return array($t[1]);}function box() { return array( array('t'=>'--1--', 'child' => array(array('t'=>2),array('t'=>2),array('t'=>2),)), array('t'=>'--2--', 'child' => array(array('t'=>2),array('t'=>2),array('t'=>2),)), array('t'=>'--3--', 'child' => array(array('t'=>2),array('t'=>2),array('t'=>2),)), array('t'=>'--4--', 'child' => array(array('t'=>2),array('t'=>2),array('t'=>2),)), array('t'=>'--5--', 'child' => array(array('t'=>2),array('t'=>2),array('t'=>2),)), array('t'=>'--6--', 'child' => array(array('t'=>2),array('t'=>2),array('t'=>2),)), );}$p = new template('布局.txt');$p->run(); //使用也做相应调整
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" dsn=body><head><meta http-equiv="Content-Type" content="text/html; charset=gb2312" /><title>{title}</title><style>/*基本信息*/body {font:12px Tahoma;margin:0px;text-align:center;background:#FFF;}a:link,a:visited {font-size:12px;text-decoration:none;}a:hover{}#side { background: #99FF99; height: 100%; width: 200px; float: left; }#side1 { background: #99FF99; height: 100%; width: 200px; float: right; }#main { background: #99FFFF; height: 100%; margin:0 200px; }/*页面层容器*/#container {width:800px;margin:10px auto}/*页面头部*/#banner {height:88px;background:url(http://avatar.csdn.net/8/7/6/2_xuzuning.jpg) no-repeat}#topmenu { width:800px; float:left;background:#fff; }#topmenu ul{ list-style-type: none; margin:10px 0 10px 40px; padding: 0px;}#topmenu li{ display:inline;padding:0 5px;}#topmenu li a{ color:#000; text-decoration:none;}#topmenu li a:hover{ color:#f00;}/*添加了float:right使得菜单位于页面右侧*/#topmenu ul {float:right;list-style:none;margin:0px;}/*页面主体*/#PageBody {width:800px;margin:0px auto;height:400px;background:#CCFF00}#Sidebar { width:200px; height:400px; float: left; background:#CCc }# MainBody {float: left; height:400px; margin-left:200px; background:#CCFF00 }/*页面底部*/#Footer {width:800px;margin:0px auto;height:50px;background:#00FFFF}.TreeView,.TreeView ul{ margin:0px; padding:0px; list-style:none; font-size:12px; }.TreeView li{ padding-left:16px; text-indent:16px; line-height:14px; background:transparent url(folder.gif) 12px 2px no-repeat;}.box { background: #FFFCC4;border: 1px dotted #BAB9B8; margin: 8px;}.imgbox {display: table-cell;vertical-align:middle;width:120px;height:120px;text-align:center;/* hack for ie */*display: block;*font-size: 105px;/* end */border: 5px solid red;}.imgbox img {vertical-align:middle;}</style></head><body><div id="container"><!--页面层容器--> <div id="Header"><!--页面头部--> <div id="banner"></div> <div style='background:#CCFF00;width:100%'>{advertising}</div> <!-- 导航菜单开始 --> <div id="topmenu" style='height:24px; font-size:14pt'><ul dsn=menu><li><a href="#">{text}</a></li></ul></div> <!-- 导航菜单结束 --> </div> <div id="PageBody"><!--页面主体--><div id="side"><!--此处显示 id "side" 的内容--><div style='text-align:left'><ul class=TreeView dsn='tree'> <li >{NAME}{drill}</li></ul></div></div><div id="side1"><!--此处显示 id "side1" 的内容--></div><div id="main"> <!--此处显示 id "main" 的内容--> <div dsn=box,3 class=box> <div>{t}</div> <div dsn=child,1 style="text-align:left">{t}</div> </div> <div class="imgbox" dsn=img> <img src="{url}" alt="" /> </div></div> </div> <div id="Footer">{footer}</div></div></body></html>
ci1699的AMySQL赶超phpmyadmin;
版主这是要赶超smarty啊。
啥也不说了,弄下来试试先!
能不能加点注释啊,猛一看不太明白,仔细一看还不如猛一看
正需要模板,哈哈,太感谢了
先做个记号,等有空慢慢研究。
能不能加点注释啊,猛一看不太明白,仔细一看还不如猛一看
正需要模板,哈哈,太感谢了 你都弄下来,尝试运行一下。就应该明白了
xuzuning ?? 意外 盗号了? 很少有啊 标记 晚上看看
xuzuning ?? 意外 盗号了? 很少有啊 标记 晚上看看 你上次不是要我晾我的模板引擎吗?当时包在工具箱中,这次剥离出来了
确实牛B了。强人那。
围观教科书...过两天仔细品读.
Fatal error: Call to undefined function find_child() in E:\test.local\test.php on line 51
出现了这个错误。是怎么回事啊?
find_child() 函数是我上次发的 两个不用递归的树形数组构造函数 中的一个
不错啊支持了呵呵
不理解了:
Warning: include() [function.include]: data:// wrapper is disabled in the server configuration by allow_url_include=0 in \path\template_csdn\template_class.php on line 13Warning: include(data://,<?php $_st=$_var=array();?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"><?php if(isset($_var))$_st[]=$_var;foreach((isset($_var['body'])?$_var['body']:$this->body('0','')) as $_key=>$_var){?> <head> <meta name="generator" content="HTML Tidy, see www.w3.org" /> <meta http-equiv="Content-Type" content= "text/html; charset=gb2312" /> <title><?php echo isset($_var['title'])?$_var['title']:'';?></title> <style type="text/css"> /*»ù±¾ÐÅÏ¢*/ body {font:12px Tahoma;margin:0px;text-align:center;background:#FFF;} a:link,a:visited {font-size:12px;text-decoration:none;} a:hover{} #side { background: #99FF99; height: 100%; width: 200px; float: left; } in \path\template_csdn\template_class.php on line 13Warning: include() [function.include]: Failed opening 'data://,<?php $_st=$_var=array();?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"><?php if(isset($_var))$_st[]=$_var;foreach((isset($_var['body'])?$_var['body']:$this->body('0','')) as $_key=>$_var){?> <head> <meta name="generator" content="HTML Tidy, see www.w3.org" /> <meta http-equiv="Content-Type" content= "text/html; charset=gb2312" /> <title><?php echo isset($_var['title'])?$_var['title']:'';?></title> <style type="text/css"> /*»ù±¾ÐÅÏ¢*/ body {font:12px Tahoma;margin:0px;text-align:center;background:#FFF;} a:link,a:visited {font-size:12px;text-decoration:none;} a:hover{} #si in \path\template_csdn\template_class.php on line 13
不理解了:
HTML code
Warning: include() [function.include]: data:// wrapper is disabled in the server configuration by allow_url_include=0 in \path\template_csdn\template_class.php on line 13
Warning……
忽略了一点:要求 php.ini 中 allow_url_include = on
前一段调试 SAE 打开的。他可以用 saemc:// 访问缓存,我这样写只需换个资源头就可以在他那里用了
把形如
include 'data://,' . $_code;
的改成形如
eval('?>' . $_code);
的即可
强烈支持~~
先占个好位置。。回头研究哈。
枪神你太有爱了。
有大家的支持,不得不用心去做了。
ci1699的AMySQL赶超phpmyadmin;
版主这是要赶超smarty啊。
啥也不说了,弄下来试试先!
#include "data://," . join('<', $this->data);#改成:include eval(join('<', $this->data));#AND#include 'data://,' . $_code;#改成include eval('?>' . $_code);#Error:#Parse error: syntax error, unexpected '<' in \path\template_csdn\template_class.php(12) : eval()'d code on line 1Warning: include() [function.include]: Filename cannot be empty in \path\template_csdn\template_class.php on line 12Warning: include() [function.include]: Failed opening '' for inclusion (include_path='.;C:\php\pear') in \path\template_csdn\template_class.php on line 12
PHP code
#include "data://," . join('<', $this->data);
#改成:
include eval(join('<', $this->data));
#AND
#include 'data://,' . $_code;
#改成
include eval('?>' . $_code);
#Error:
#Parse error: syntax ……
哈哈,问题相同啊,刚要问呢,这都出来了,等LZ解答,最好打个包最好哈
测试成功啦,只要把find_child()函数引进,把allow_url_include = on
就可正常运行,FF下图片确实显示位置不一至,慢慢分析学习,再次感谢分享
好啊挖坟
先占个位置。静等终极版本
学习PHP中……
不错 支持一个
可不可以缓存到一个大的cache文件里。不太理解模版的用意是什么
function body() { return array( array( 'title' => '布局', 'advertising' => '一贯喜欢用表格布局,这种 DIV+CSS 方式很让人头疼的', 'menu' => array( array('text' => '首页' ), array('text' => '博客' ), array('text' => '设计' ), array('text' => '相册' ), array('text' => '论坛' ), array('text' => '关于' ), ), 'footer' => '为什么表现不一样呢,IE就是对齐的', ), );}
cope下来试一试,学习下。
大晚上的还有人喷口水。
单纯的过来看看..
哦,还要小小研究下。
性能呢?使用了eval函数,这个尽量别用,很损耗性能的。
果断收藏!
性能呢?使用了eval函数,这个尽量别用,很损耗性能的。
首先eval不是函数,原版的执行方法在注释的地方。至于性能,你测试过吗?
=======================
我觉得亮点在数据从模板中决定需要调用的函数
模板信息传递很巧妙。。。另外由此会使得,模板中load其他模板,会变得稍微复杂一些吧
仅作为核心功能演示吗?好像仅支持dsn=函数名,而没考虑类方法?
收藏~~~
引用 32 楼 的回复:
性能呢?使用了eval函数,这个尽量别用,很损耗性能的。
首先eval不是函数,原版的执行方法在注释的地方。至于性能,你测试过吗?
=======================
我觉得亮点在数据从模板中决定需要调用的函数
模板信息传递很巧妙。。。另外由此会使得,模板中load其他模板,会变得稍微复杂一些吧
仅作为核心功能演示吗?好……
没有细看版主的引擎具体实现.不过有几个看法:
1. 如果允许模板文件中调用任意函数(或加入PHP代码), 就很难避免开发人员在模板中嵌入业务逻辑, 也许是人员素质的问题, 但是, 从软件工程的角度来看, 我们应该尽量避免人员素质带来的问题
2. 使用正则表达式匹配处理的模板引擎都有硬伤(ThinkPHP自带的模板引擎存在下面两个问题):
a) 要支持多种复杂的语法, 通常都会进行多次匹配, 带来对字符串的多次扫描, 产生不必要浪费
b) 通常都不对字面量处理(涉及引号配对, 转义检查, 非标准HTML兼容等处理, 用正则难度太大), 使得引号内的特殊字符无法使用
いくつかの質問への回答
#28
[問題] 既知のパラメータの方が優れていますが、これらのデータがデータベースから取得された場合、クエリ結果セットを一緒に大きな配列にプッシュする必要があります
[回答] まさにこの構造はデータのほとんどがデータベースから取得されるため、これが選択されます。ほとんどのデータベース クラスは、配列内の結果セットを返すために使用される fetchall メソッドを提供します。そのため、データ ソース関数は単純に DB::fetchall($sql); を返すだけで済みます。ファイルのコードは $p = new template('layout.txt');
インスタンス化、この $p に目立った性能や意味がないと感じるのはなぜですか
[回答] echo $ でテンプレートの翻訳されたコードを確認できるからですp;
[質問] 良いテンプレート エンジンは次のようになります
$p=new ',$xxx);
実際、これは Smarty の形式です (人気があるので当然です)
[回答]あなたが説明しているのは、従来の「プッシュ」テンプレート エンジンです。テンプレートに必要かどうかに関係なく、データはテンプレート エンジンのバッファーに割り当てる必要があります
そして、私のものは「プル」テンプレート エンジンです。テンプレートが必要な場合にのみ、テンプレート エンジンからデータを要求します
[問題] ジュニア プログラマが使用するのに適した方法を無視して、array(array(array()()) を使いすぎます。必ずしも配列である必要はありません
[回答] 前述したように、データベースからのデータはデータベース クラスの fetchall メソッドを通じて取得できます。データをさらに処理するために、いくつかの関数も用意しました
例: find_child 関数。ツリー構造の生成に使用できます。「ブレッドクラム」の生成に必要なデータは find_parent 関数で使用できます
テンプレート エンジンを使用する目的は、開発者がアルゴリズムの実装に集中できるようにすることです。配列関数を使いこなせるようにしてください
【質問】 テンプレートファイルとはいえ、HTMLの仕様に準拠する必要がありますが、元のHTMLタグはあまり変更すべきではありません(カスタム属性もありますが)。 JavaScript の特殊効果の処理に使用されます
一見すると専門的ではないように見えますが、独自のカスタム属性を使用するのが最善です。これは初心者がそれをよりよく理解できるようにするものであり、不親切な方法で HTML を破壊するべきではありません。 3 つのコントロールを完了するには 1 つの属性を追加するだけで十分です
#32
[質問] パフォーマンスについてはどうですか? eval 関数を使用すると、非常にパフォーマンスが高くなります
[回答] eval を使用するのは、 include を使用するのと同じです
#33
[問題] テンプレートに他のテンプレートを読み込むと、少し複雑になります。はい、ツール編集を使用するため、テンプレートにテンプレートを埋め込むことは考慮しないでください
コマンド、関数、条件文の機能を実装するには、var_callback メソッドを拡張するだけで済みます
【質問】 dsn=関数名のみがサポートされ、クラスメソッドは考慮されません
[回答] 私の目標は、テンプレートとしての HTML ドキュメントに変更を加える必要性を可能な限り減らし、問題を PHP に任せることです。完了
#36
[問題] 正規表現のマッチング処理を使用するテンプレート エンジンには欠陥があります
[答え] はい、しかし正規表現を使用することはできません 必要なコンポーネントを特定するのは困難です
ただし、正規表現のパフォーマンスは問題ありません。 PHP の式処理が大幅に改善されました。実際の測定では、文字列長が 50 バイトを超えると、preg_split の方がexplode よりも高速になることがわかりました。
テストは成功しました。find_child() 関数を導入して、allow_url_include = on
とすると、FF 内の画像が実際にさまざまな位置に表示されます。ゆっくりと分析して学習してください。これは確かに必要です。 find_child() 関数を導入しましたが、これは無視されました。最後に、結果が 2 つあります:
IE8:
FF:
私はそれを感じます、そしてそれは確かに #28 が言ったように、配列が多くのレベルを持つ場合、それは少し複雑に見えます、私はまだ慣れています。データベースに。
でも、これまで触れたことのない知識構造をたくさん見ることができて、とても勉強になりました。
何か良いことをマークしてください!
问个问题
如何解决
你描述的是传统的“推”方式模板引擎。无论模板是否需要,都要讲数据 assign 到模板引擎的缓冲区去
而我的这个是“拉”方式模板引擎。只在模板需要时才向模板引擎请求数据
看你的文件运行顺序可知,这种说法不属实,首先运行的是 php文件,然后读取html,模板中用的是
if(file_exists($s)) $s = file_get_contents($s); 也就不存在【只在模板需要时才向模板引擎请求数据】这种说法了,而是先读取整个模板,然后根据里面的自定义属性,进行替换操作。
如果反过来,运行html文件,然后碰到自定义属性的时候,调取所需数据,这才符合
【只在模板需要时才向模板引擎请求数据】这种说法
不会php的飘过,支持楼主分享精神
由于控制权在 php ,不在模板里
<ul dsn='ranking'> <li class='class{n}'>{txt}</li></ul>function ranking() { return array( array('n' => 1, 'txt' => '一'), array('n' => 2, 'txt' => '二'), array('n' => 3, 'txt' => '三'), array('n' => 0, 'txt' => '四'), array('n' => 0, 'txt' => '五'), array('n' => 0, 'txt' => '六'), array('n' => 0, 'txt' => '七'), );}