[TOC]
# 1 简单例子
> Twig的简单应用例子
~~~
<?php
require_once './vendor/autoload.php';
// 字符串渲染
// $loader = new Twig_Loader_Array(array(
// 'index' => 'Hello {{ name }}!',
// ));
// $twig = new Twig_Environment($loader);
// echo $twig->render('index', array('name' => 'Fabien'));
// 文件渲染
$loader = new Twig_Loader_Filesystem('./template');
$twig = new Twig_Environment($loader, array(
'cache' => './cache',
));
$string = $twig->render('index.html', array('name' => 'Fabien'));
?>
~~~
# 2 主要流程
> 简单例子中Twig的主要流程
> 1. 创建模板加载器 Twig_loader
> 2. 创建编译环境 Twig_environment
> 3. 编译模板 render()
# 3 编译流程
>在render()方法包含编译流程
~~~
;\Twig\Environment.php
public function render($name, array $context = array())
{
return $this->loadTemplate($name)->render($context);
}
~~~
> 模板编译入口
~~~
public function loadTemplate($name, $index = null)
{
$cls = $mainCls = $this->getTemplateClass($name);
if (null !== $index) {
$cls .= '_'.$index;
}
if (isset($this->loadedTemplates[$cls])) {
return $this->loadedTemplates[$cls];
}
if (!class_exists($cls, false)) {
$key = $this->cache->generateKey($name, $mainCls);
if (!$this->isAutoReload() || $this->isTemplateFresh($name, $this->cache->getTimestamp($key))) {
$this->cache->load($key);
}
if (!class_exists($cls, false)) {
$source = $this->getLoader()->getSourceContext($name);
$content = $this->compileSource($source);
$this->cache->write($key, $content);
$this->cache->load($key);
if (!class_exists($mainCls, false)) {
/* Last line of defense if either $this->bcWriteCacheFile was used,
* $this->cache is implemented as a no-op or we have a race condition
* where the cache was cleared between the above calls to write to and load from
* the cache.
*/
eval('?>'.$content);
}
if (!class_exists($cls, false)) {
throw new Twig_Error_Runtime(sprintf('Failed to load Twig template "%s", index "%s": cache is corrupted.', $name, $index), -1, $source);
}
}
}
// to be removed in 3.0
$this->extensionSet->initRuntime($this);
if (isset($this->loading[$cls])) {
throw new Twig_Error_Runtime(sprintf('Circular reference detected for Twig template "%s", path: %s.', $name, implode(' -> ', array_merge($this->loading, array($name)))));
}
$this->loading[$cls] = $name;
try {
$this->loadedTemplates[$cls] = new $cls($this);
} finally {
unset($this->loading[$cls]);
}
return $this->loadedTemplates[$cls];
}
~~~
>加载编译后的模板
~~~
public function compileSource(Twig_Source $source)
{
try {
return $this->compile($this->parse($this->tokenize($source)));
} catch (Twig_Error $e) {
$e->setSourceContext($source);
throw $e;
} catch (Exception $e) {
throw new Twig_Error_Syntax(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $source, $e);
}
}
~~~
>模板编译核心流程
>1.$this->tokenize()
>2.$this->parser()
>3.$this->compile()
~~~
public function tokenize(Twig_Source $source)
{
if (null === $this->lexer) {
$this->lexer = new Twig_Lexer($this);
}
return $this->lexer->tokenize($source);
}
~~~
> 调用Twig_Lexer分析模板文件生成Twig_TokenStream
~~~
public function parse(Twig_TokenStream $stream)
{
if (null === $this->parser) {
$this->parser = new Twig_Parser($this);
}
return $this->parser->parse($stream);
}
~~~
> 调用Twig_Parser解析Twig_TokenStream
~~~
public function compile(Twig_Node $node)
{
if (null === $this->compiler) {
$this->compiler = new Twig_Compiler($this);
}
return $this->compiler->compile($node)->getSource();
}
~~~
> 调用Twig_Compiler编译Twig_Node
# 4 流程总结
> 1. 创建加载器 Twig_Loader
> 2. 创建编译环境 Twig_Environment
> 3. 模板文件解析 Twig_Lexer
> 4. 模板字符串解析 Twig_Parser
> 5. 模板节点编译 Twig_Compiler