- optimization of inheritance processing

This commit is contained in:
uwetews
2016-05-10 03:54:56 +02:00
parent 608064e5f2
commit 1fbf16afed
13 changed files with 173 additions and 133 deletions

View File

@@ -1,4 +1,7 @@
 ===== 3.1.30-dev ===== (xx.xx.xx)  ===== 3.1.30-dev ===== (xx.xx.xx)
10.05.2016
- optimization of inheritance processing
07.05.2016 07.05.2016
-bugfix Only variables should be assigned by reference https://github.com/smarty-php/smarty/issues/227 -bugfix Only variables should be assigned by reference https://github.com/smarty-php/smarty/issues/227

View File

@@ -121,7 +121,7 @@ class Smarty extends Smarty_Internal_TemplateBase
/** /**
* smarty version * smarty version
*/ */
const SMARTY_VERSION = '3.1.30-dev/67'; const SMARTY_VERSION = '3.1.30-dev/68';
/** /**
* define variable scopes * define variable scopes

View File

@@ -77,69 +77,13 @@ class Smarty_Internal_Block
* - if outer level {block} of child template ($state == 1) save it as child root block * - if outer level {block} of child template ($state == 1) save it as child root block
* - otherwise process inheritance and render * - otherwise process inheritance and render
* *
* @param \Smarty_Internal_Template $tpl * @param string $name block name
* @param int|null $tplIndex index of outer level {block} if nested * @param int|null $tplIndex index of outer level {block} if nested
*/ */
public function __construct(Smarty_Internal_Template $tpl, $name, $tplIndex = null) public function __construct($name, $tplIndex)
{ {
$this->name = $name; $this->name = $name;
$inheritance = &$tpl->ext->_inheritance; $this->tplIndex = $tplIndex;
$this->tplIndex = $tplIndex ? $tplIndex : $inheritance->tplIndex;
if (isset($inheritance->childRoot[ $this->name ])) {
$this->child = $inheritance->childRoot[ $this->name ];
}
if ($inheritance->state == 1) {
$inheritance->childRoot[ $this->name ] = $this;
return;
}
// make sure we got child block of child template of current block
while ($this->child && $this->tplIndex <= $this->child->tplIndex) {
$this->child = $this->child->child;
}
$this->process($tpl);
}
/**
* Goto child block or render this
*
* @param \Smarty_Internal_Template $tpl
* @param \Smarty_Internal_Block|null $parent
*/
public function process(Smarty_Internal_Template $tpl, Smarty_Internal_Block $parent = null)
{
$inheritance = &$tpl->ext->_inheritance;
if ($this->hide && !isset($this->child)) {
return;
}
if (isset($this->child) && $this->child->hide && !isset($this->child->child)) {
$this->child = null;
}
$this->parent = $parent;
if ($this->append && !$this->prepend && isset($parent)) {
$this->callParent($tpl);
}
if ($this->callsChild || !isset($this->child) || ($this->child->hide && !isset($this->child->child))) {
$this->subTemplateNesting = 0;
array_unshift($inheritance->blockCallStack, $this);
$this->callBlock($tpl);
array_shift($inheritance->blockCallStack);
} else {
$this->child->process($tpl, $this);
}
if ($this->prepend && isset($parent)) {
$this->callParent($tpl);
if ($this->append) {
if ($this->callsChild || !isset($this->child) || ($this->child->hide && !isset($this->child->child))) {
$this->subTemplateNesting = 0;
array_unshift($inheritance->blockCallStack, $this);
$this->callBlock($tpl);
array_shift($inheritance->blockCallStack);
} else {
$this->child->process($tpl, $this);
}
}
}
$this->parent = null;
} }
/** /**
@@ -150,35 +94,4 @@ class Smarty_Internal_Block
public function callBlock(Smarty_Internal_Template $tpl) public function callBlock(Smarty_Internal_Template $tpl)
{ {
} }
/**
* Render child on {$smarty.block.child}
*
* @param \Smarty_Internal_Template $tpl
*/
public function callChild(Smarty_Internal_Template $tpl)
{
if (isset($this->child)) {
$this->child->process($tpl, $this);
}
}
/**
* Render parent on {$smarty.block.parent} or {block append/prepend} *
*
* @param \Smarty_Internal_Template $tpl
*
* @throws \SmartyException
*/
public function callParent(Smarty_Internal_Template $tpl)
{
if (isset($this->parent)) {
$this->parent->subTemplateNesting = 0;
array_unshift($tpl->ext->_inheritance->blockCallStack, $this->parent);
$this->parent->callBlock($tpl);
array_shift($tpl->ext->_inheritance->blockCallStack);
} else {
throw new SmartyException("inheritance: illegal {\$smarty.block.parent} or {block append/prepend} used in parent template '{$tpl->ext->_inheritance->sources[$this->tplIndex]->filepath}' block '{$this->name}'");
}
}
} }

View File

@@ -121,7 +121,7 @@ class Smarty_Internal_Compile_Block extends Smarty_Internal_Compile_Shared_Inher
$compiler->has_code = true; $compiler->has_code = true;
$compiler->suppressNocacheProcessing = true; $compiler->suppressNocacheProcessing = true;
$compiler->_cache[ 'blockParams' ][ $compiler->_cache[ 'blockNesting' ] ][ 'callsChild' ] = 'true'; $compiler->_cache[ 'blockParams' ][ $compiler->_cache[ 'blockNesting' ] ][ 'callsChild' ] = 'true';
$output = "<?php \n\$this->callChild(\$_smarty_tpl);\n?>\n"; $output = "<?php \n\$_smarty_tpl->inheritance->callChild(\$_smarty_tpl, \$this);\n?>\n";
return $output; return $output;
} }
@@ -141,7 +141,7 @@ class Smarty_Internal_Compile_Block extends Smarty_Internal_Compile_Shared_Inher
} }
$compiler->suppressNocacheProcessing = true; $compiler->suppressNocacheProcessing = true;
$compiler->has_code = true; $compiler->has_code = true;
$output = "<?php \n\$this->callParent(\$_smarty_tpl);\n?>\n"; $output = "<?php \n\$_smarty_tpl->inheritance->callParent(\$_smarty_tpl, \$this);\n?>\n";
return $output; return $output;
} }
} }
@@ -180,16 +180,9 @@ class Smarty_Internal_Compile_Blockclose extends Smarty_Internal_Compile_Shared_
$_functionCode = $compiler->parser->current_buffer; $_functionCode = $compiler->parser->current_buffer;
// setup buffer for template function code // setup buffer for template function code
$compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template(); $compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template();
if ($compiler->template->source->type == 'file') {
$sourceInfo = $compiler->template->source->filepath;
} else {
$basename = $compiler->template->source->handler->getBasename($compiler->template->source);
$sourceInfo =
$compiler->template->source->type . ':' . ($basename ? $basename : $compiler->template->source->name);
}
$output = "<?php\n"; $output = "<?php\n";
$output .= "/* {block {$_name}} {$sourceInfo} */\n"; $output .= "/* {block {$_name}} */\n";
$output .= "class {$_className} extends Smarty_Internal_Block\n"; $output .= "class {$_className} extends Smarty_Internal_Block\n";
$output .= "{\n"; $output .= "{\n";
foreach ($_block as $property => $value) { foreach ($_block as $property => $value) {
@@ -238,9 +231,9 @@ class Smarty_Internal_Compile_Blockclose extends Smarty_Internal_Compile_Shared_
$compiler->parser->current_buffer = $_buffer; $compiler->parser->current_buffer = $_buffer;
$output = "<?php \n"; $output = "<?php \n";
if ($compiler->_cache[ 'blockNesting' ] == 1) { if ($compiler->_cache[ 'blockNesting' ] == 1) {
$output .= "new {$_className}(\$_smarty_tpl, $_name);\n"; $output .= "\$_smarty_tpl->inheritance->instanceBlock(\$_smarty_tpl, '$_className', $_name);\n";
} else { } else {
$output .= "new {$_className}(\$_smarty_tpl, $_name, \$this->tplIndex);\n"; $output .= "\$_smarty_tpl->inheritance->instanceBlock(\$_smarty_tpl, '$_className', $_name, \$this->tplIndex);\n";
} }
$output .= "?>\n"; $output .= "?>\n";
$compiler->_cache[ 'blockNesting' ] --; $compiler->_cache[ 'blockNesting' ] --;

View File

@@ -99,7 +99,7 @@ class Smarty_Internal_Compile_Extends extends Smarty_Internal_Compile_Shared_Inh
private function compileEndChild(Smarty_Internal_TemplateCompilerBase $compiler) private function compileEndChild(Smarty_Internal_TemplateCompilerBase $compiler)
{ {
$compiler->parser->template_postfix[] = new Smarty_Internal_ParseTree_Tag($compiler->parser, $compiler->parser->template_postfix[] = new Smarty_Internal_ParseTree_Tag($compiler->parser,
"<?php \$_smarty_tpl->ext->_inheritance->endChild(\$_smarty_tpl);\n?>\n"); "<?php \$_smarty_tpl->inheritance->endChild(\$_smarty_tpl);\n?>\n");
} }
/** /**

View File

@@ -297,8 +297,8 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase
if (!($tpl->source->handler->uncompiled) && $tpl->source->exists) { if (!($tpl->source->handler->uncompiled) && $tpl->source->exists) {
$compiler->parent_compiler->mergedSubTemplatesData[ $uid ][ $t_hash ][ 'uid' ] = $compiler->parent_compiler->mergedSubTemplatesData[ $uid ][ $t_hash ][ 'uid' ] =
$tpl->source->uid; $tpl->source->uid;
if (isset($compiler->template->ext->_inheritance)) { if (isset($compiler->template->inheritance)) {
$tpl->ext->_inheritance = clone $compiler->template->ext->_inheritance; $tpl->inheritance = clone $compiler->template->inheritance;
} }
$tpl->compiled = new Smarty_Template_Compiled(); $tpl->compiled = new Smarty_Template_Compiled();
$tpl->compiled->nocache_hash = $compiler->parent_compiler->template->compiled->nocache_hash; $tpl->compiled->nocache_hash = $compiler->parent_compiler->template->compiled->nocache_hash;

View File

@@ -40,7 +40,7 @@ class Smarty_Internal_Compile_Shared_Inheritance extends Smarty_Internal_Compile
*/ */
static function postCompile(Smarty_Internal_TemplateCompilerBase $compiler, $initChildSequence = false) static function postCompile(Smarty_Internal_TemplateCompilerBase $compiler, $initChildSequence = false)
{ {
$compiler->prefixCompiledCode .= "<?php \$_smarty_tpl->ext->_inheritance->init(\$_smarty_tpl, " . $compiler->prefixCompiledCode .= "<?php \$_smarty_tpl->_loadInheritance();\n\$_smarty_tpl->inheritance->init(\$_smarty_tpl, " .
var_export($initChildSequence, true) . ");\n?>\n"; var_export($initChildSequence, true) . ");\n?>\n";
} }
} }

View File

@@ -10,7 +10,6 @@
* @subpackage PluginsInternal * @subpackage PluginsInternal
* @author Uwe Tews * @author Uwe Tews
* *
* @property Smarty_Internal_Runtime_Inheritance $_inheritance
* @property Smarty_Internal_Runtime_TplFunction $_tplFunction * @property Smarty_Internal_Runtime_TplFunction $_tplFunction
* @property Smarty_Internal_Runtime_Foreach $_foreach * @property Smarty_Internal_Runtime_Foreach $_foreach
* @property Smarty_Internal_Runtime_WriteFile $_writeFile * @property Smarty_Internal_Runtime_WriteFile $_writeFile

View File

@@ -45,7 +45,7 @@ class Smarty_Internal_Resource_File extends Smarty_Resource
} }
$parentPath = $_template->parent->source->filepath; $parentPath = $_template->parent->source->filepath;
// if we are inside an {block} tag the path must be relative to template of {block} // if we are inside an {block} tag the path must be relative to template of {block}
if (isset($_template->ext->_inheritance) && $path = $_template->ext->_inheritance->getBlockFilepath()) { if (isset($_template->inheritance) && $path = $_template->inheritance->getBlockFilepath()) {
$parentPath = $path; $parentPath = $path;
} }
// normalize path // normalize path

View File

@@ -71,8 +71,8 @@ class Smarty_Internal_Runtime_Inheritance
{ {
// if called while executing parent template it must be a sub-template with new inheritance root // if called while executing parent template it must be a sub-template with new inheritance root
if ($initChild && $this->state == 3 && (strpos($tpl->template_resource, 'extendsall') === false)) { if ($initChild && $this->state == 3 && (strpos($tpl->template_resource, 'extendsall') === false)) {
$tpl->ext->_inheritance = new Smarty_Internal_Runtime_Inheritance(); $tpl->inheritance = new Smarty_Internal_Runtime_Inheritance();
$tpl->ext->_inheritance->init($tpl, $initChild, $blockNames); $tpl->inheritance->init($tpl, $initChild, $blockNames);
return; return;
} }
// start of child sub template(s) // start of child sub template(s)
@@ -83,6 +83,8 @@ class Smarty_Internal_Runtime_Inheritance
ob_start(); ob_start();
} }
$this->inheritanceLevel ++; $this->inheritanceLevel ++;
$tpl->startRenderCallbacks[ 'inheritance' ] = array($this, 'subTemplateStart');
$tpl->endRenderCallbacks[ 'inheritance' ] = array($this, 'subTemplateEnd');
} }
// in parent state {include} will not increment template index // in parent state {include} will not increment template index
if ($this->state != 3) { if ($this->state != 3) {
@@ -110,6 +112,114 @@ class Smarty_Internal_Runtime_Inheritance
} }
} }
/**
* Smarty_Internal_Block constructor.
* - if outer level {block} of child template ($state == 1) save it as child root block
* - otherwise process inheritance and render
*
* @param \Smarty_Internal_Template $tpl
* @param $className
* @param string $name
* @param int|null $tplIndex index of outer level {block} if nested
*/
public function instanceBlock(Smarty_Internal_Template $tpl, $className, $name, $tplIndex = null)
{
$block = new $className($name, $tplIndex ? $tplIndex : $this->tplIndex);
if (isset($this->childRoot[ $name ])) {
$block->child = $this->childRoot[ $name ];
}
if ($this->state == 1) {
$this->childRoot[ $name ] = $block;
return;
}
// make sure we got child block of child template of current block
while ($block->child && $block->tplIndex <= $block->child->tplIndex) {
$block->child = $block->child->child;
}
$this->process($tpl, $block);
}
/**
* Goto child block or render this
*
* @param \Smarty_Internal_Template $tpl
* @param \Smarty_Internal_Block $block
* @param \Smarty_Internal_Block|null $parent
*
* @throws \SmartyException
*/
public function process(Smarty_Internal_Template $tpl, Smarty_Internal_Block $block,
Smarty_Internal_Block $parent = null)
{
if ($block->hide && !isset($block->child)) {
return;
}
if (isset($block->child) && $block->child->hide && !isset($block->child->child)) {
$block->child = null;
}
$block->parent = $parent;
if ($block->append && !$block->prepend && isset($parent)) {
$this->callParent($tpl, $block);
}
if ($block->callsChild || !isset($block->child) || ($block->child->hide && !isset($block->child->child))) {
$block->subTemplateNesting = 0;
$this->blockCallStack[] = $block;
$block->callBlock($tpl);
array_pop($this->blockCallStack);
} else {
$this->process($tpl, $block->child, $block);
}
if ($block->prepend && isset($parent)) {
$this->callParent($tpl, $block);
if ($block->append) {
if ($block->callsChild || !isset($block->child) ||
($block->child->hide && !isset($block->child->child))
) {
$block->subTemplateNesting = 0;
$this->blockCallStack[] = $block;
$block->callBlock($tpl);
array_pop($this->blockCallStack);
} else {
$this->process($tpl, $block->child, $block);
}
}
}
$block->parent = null;
}
/**
* Render child on {$smarty.block.child}
*
* @param \Smarty_Internal_Template $tpl
* @param \Smarty_Internal_Block $block
*/
public function callChild(Smarty_Internal_Template $tpl, Smarty_Internal_Block $block)
{
if (isset($block->child)) {
$this->process($tpl, $block->child, $block);
}
}
/**
* Render parent on {$smarty.block.parent} or {block append/prepend} *
*
* @param \Smarty_Internal_Template $tpl
* @param \Smarty_Internal_Block $block
*
* @throws \SmartyException
*/
public function callParent(Smarty_Internal_Template $tpl, Smarty_Internal_Block $block)
{
if (isset($block->parent)) {
$block->parent->subTemplateNesting = 0;
$this->blockCallStack[] = $block->parent;
$block->parent->callBlock($tpl);
array_pop($this->blockCallStack);
} else {
throw new SmartyException("inheritance: illegal {\$smarty.block.parent} or {block append/prepend} used in parent template '{$tpl->inheritance->sources[$block->tplIndex]->filepath}' block '{$block->name}'");
}
}
/** /**
* Return source filepath of current {block} if not in sub-template * Return source filepath of current {block} if not in sub-template
* *
@@ -117,8 +227,9 @@ class Smarty_Internal_Runtime_Inheritance
*/ */
public function getBlockFilepath() public function getBlockFilepath()
{ {
if (!empty($this->blockCallStack) && $this->blockCallStack[ 0 ]->subTemplateNesting === 0) { $count = count($this->blockCallStack);
return $this->sources[ $this->blockCallStack[ 0 ]->tplIndex ]->filepath; if ($count && $this->blockCallStack[ $count - 1 ]->subTemplateNesting === 0) {
return $this->sources[ $this->blockCallStack[ $count - 1 ]->tplIndex ]->filepath;
} }
return false; return false;
} }
@@ -128,8 +239,9 @@ class Smarty_Internal_Runtime_Inheritance
*/ */
public function subTemplateStart() public function subTemplateStart()
{ {
if (!empty($this->blockCallStack)) { $count = count($this->blockCallStack);
$this->blockCallStack[ 0 ]->subTemplateNesting ++; if ($count) {
$this->blockCallStack[ $count - 1 ]->subTemplateNesting ++;
} }
} }
@@ -138,8 +250,9 @@ class Smarty_Internal_Runtime_Inheritance
*/ */
public function subTemplateEnd() public function subTemplateEnd()
{ {
if (!empty($this->blockCallStack)) { $count = count($this->blockCallStack);
$this->blockCallStack[ 0 ]->subTemplateNesting --; if ($count && $this->blockCallStack[ $count - 1 ]->subTemplateNesting) {
$this->blockCallStack[ $count - 1 ]->subTemplateNesting --;
} }
} }
} }

View File

@@ -46,6 +46,13 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
*/ */
public $source = null; public $source = null;
/**
* Inheritance runtime extension
*
* @var Smarty_Internal_Runtime_Inheritance
*/
public $inheritance = null;
/** /**
* Template resource * Template resource
* *
@@ -256,7 +263,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
$smarty = &$this->smarty; $smarty = &$this->smarty;
$_templateId = $smarty->_getTemplateId($template, $cache_id, $compile_id, $caching, $tpl); $_templateId = $smarty->_getTemplateId($template, $cache_id, $compile_id, $caching, $tpl);
// recursive call ? // recursive call ?
if ($tpl->_getTemplateId() != $_templateId) { if (isset($tpl->templateId) ? $tpl->templateId : $tpl->_getTemplateId() != $_templateId) {
// already in template cache? // already in template cache?
if (isset($smarty->_cache[ 'tplObjects' ][ $_templateId ])) { if (isset($smarty->_cache[ 'tplObjects' ][ $_templateId ])) {
// copy data from cached object // copy data from cached object
@@ -330,10 +337,6 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
} }
} }
$tpl->_cache = array(); $tpl->_cache = array();
if (isset($tpl->ext->_inheritance)) {
$saved_inheritance = $tpl->ext->_inheritance;
$saved_inheritance->subTemplateStart();
}
if (isset($uid)) { if (isset($uid)) {
if ($smarty->debugging) { if ($smarty->debugging) {
$smarty->_debug->start_template($tpl); $smarty->_debug->start_template($tpl);
@@ -351,12 +354,6 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
$tpl->render(); $tpl->render();
} }
} }
if (isset($saved_inheritance)) {
$saved_inheritance->subTemplateEnd();
$tpl->ext->_inheritance = $saved_inheritance;
} else {
unset($tpl->ext->_inheritance);
}
} }
/** /**
@@ -553,6 +550,29 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
} }
} }
/**
* Load inheritance object
*
*/
public function _loadInheritance()
{
if (!isset($this->inheritance)) {
$this->inheritance = new Smarty_Internal_Runtime_Inheritance();
}
}
/**
* Unload inheritance object
*
*/
public function _cleanUp()
{
$this->tpl_function = array();
$this->startRenderCallbacks = array();
$this->endRenderCallbacks = array();
$this->inheritance = null;
}
/** /**
* Load compiler object * Load compiler object
* *

View File

@@ -198,9 +198,8 @@ abstract class Smarty_Internal_TemplateBase extends Smarty_Internal_Data
$template->tpl_vars = array_merge(Smarty::$global_tpl_vars, $template->tpl_vars); $template->tpl_vars = array_merge(Smarty::$global_tpl_vars, $template->tpl_vars);
} }
$result = $template->render(false, $function); $result = $template->render(false, $function);
unset($template->ext->_inheritance); $template->_cleanUp();
$template->tpl_function = array(); if ($saveVars) {
if ($saveVars) {
$template->tpl_vars = $savedTplVars; $template->tpl_vars = $savedTplVars;
$template->config_vars = $savedConfigVars; $template->config_vars = $savedConfigVars;
} else { } else {

View File

@@ -216,7 +216,7 @@ abstract class Smarty_Resource
) { ) {
$parentPath = $obj->parent->source->filepath; $parentPath = $obj->parent->source->filepath;
// if we are inside an {block} tag the path must be relative to template of {block} // if we are inside an {block} tag the path must be relative to template of {block}
if (isset($obj->ext->_inheritance) && $path = $obj->ext->_inheritance->getBlockFilepath()) { if (isset($obj->inheritance) && $path = $obj->inheritance->getBlockFilepath()) {
$parentPath = $path; $parentPath = $path;
} }
$name = $smarty->_realpath(dirname($parentPath) . DS . $name); $name = $smarty->_realpath(dirname($parentPath) . DS . $name);