Bug #15752
closedFaster "substituteConstants"
0%
Description
"substituteConstants" for typoscript is using loop and str_replace, which has a poor performance. O(M x N).
Neither longer typoscript setup or one more constants(even not used) will increase processing time a lot.
By replacing it into preg_replace_callback, it can finish the job with only 20% of time.
class.t3lib_TStemplate.php
---- 1.27.2.1 on CVS ----
function substituteConstants($all) {
if ($this->tt_track) $GLOBALS['TT']->setTSlogMessage('Constants to substitute: '.count($this->flatSetup));
reset($this->flatSetup);
while (list($const,$val)=each($this->flatSetup)) {
if (!is_array($val)) {
$all = str_replace('{$'.$const.'}',$val,$all);
}
}
return $all;
}
---- modified ----
function substituteConstantsCallBack($matches) {
return isset ($this->flatSetup[$matches1]) ? $this->flatSetup[$matches1] : $matches0;
}
function substituteConstants($all) {
if ($this->tt_track)
$GLOBALS['TT']->setTSlogMessage('Constants to substitute: '.count($this->flatSetup));
return preg_replace_callback('/\{\$(.+?)\}/', array ($this, 'substituteConstantsCallBack'), $all);
}
(issue imported from #M2743)
Files
Updated by Wolfgang Klinger over 18 years ago
That's true for this method but not for the similar method in tsparser_ext (you didn't mention here), so I will only change the method in t3lib_tstemplate
(don't ask me why)
Updated by old_hkdennis2k over 18 years ago
I think the same logic can be apply into substituteConstants in tsparser_ext
You just have to wrote two more different callback.
Beside, Why put the switch in the loop??
put it outside the loop can be faster.
(i.e. It still do loop on the flatSetup even "untouched")
----
function substituteConstantsConstCallBack($matches) {
if(isset ($this->flatSetup[$matches1])){
return '##'.$this->Cmarker.'_B##{$'.$matches0.'}##'.$this->Cmarker.'_E##';
}else{
return $matches0;
}
}
function substituteConstantsSubstCallBack($matches) {
if(isset ($this->flatSetup[$matches1])){
return '##'.$this->Cmarker.'_B##{$'.$this->flatSetup[$matches1].'}##'.$this->Cmarker.'_E##';
}else{
return $matches0;
}
}
function substituteConstantsCallBack($matches) {
return isset ($this->flatSetup[$matches1]) ? $this->flatSetup[$matches1] : $matches0;
}
function substituteConstants($all) {
switch($this->constantMode) {
case 'untouched':
return all;
case 'const':
$this->Cmarker=substr(md5(uniqid("")),0,6);
return preg_replace_callback('/\{\$(.+?)\}/', array ($this, 'substituteConstantsConstCallBack'), $all);
case 'subst':
$this->Cmarker=substr(md5(uniqid("")),0,6);
return preg_replace_callback('/\{\$(.+?)\}/', array ($this, 'substituteConstantsSubstCallBack'), $all);
default:
return preg_replace_callback('/\{\$(.+?)\}/', array ($this, 'substituteConstantsCallBack'), $all);
}
}
function substituteCMarkers($all) {
switch($this->constantMode) {
case 'const':
case 'subst':
$all = str_replace(
array('##'.$this->Cmarker.'_B##','##'.$this->Cmarker.'_E##'),
array('<font color="green"><B>','</b></font>'),
$all);
default:
}
return $all;
}
Updated by Wolfgang Klinger over 18 years ago
I found a bug in my test code, sorry, I'll post it ASAP to the core list.
Updated by Stanislas Rolland over 18 years ago
When CVS version 1.27.2.2 is used as in TYPO3 4.0RC1, constants are not correctly replaced.
In the case I encountered, constants assigned to other constants are not correctly replaced.
Reverting to 1.27.2.1 corrects the problem.
Updated by old_hkdennis2k over 18 years ago
In the case I encountered, constants assigned to other constants are not correctly replaced.
In fact, the old substituteConstants was not correctly replaced too.
The "constants assigned to other constants" should be resloved and report error for any recursive loop.
I forget I did modified some where else, and make it reslove "constants assigned to other constants" at constant parse time. ( It does make sense and faster)
-----
What SHOULD the ideal final value in the folloing example?
$abc=abc
$useabc={$abc}
$abc=def
$x=x
$y=y
$xyz=${x}${y}${z}
$z=z
$inner=inner
$inner2=inner2
$outer={${$inner}2}
Updated by Wolfgang Klinger over 18 years ago
Please test the attached patch (bug2743_followup.diff), this should fix the issue with constants in constants.
I'll commit it to CVS if no one complains.
Updated by Michael Stucki over 18 years ago
Patch looks good to me, but please add some comments that explain why you are going three times over the loop (I suppose this is just an assumption?)
Updated by Wolfgang Klinger over 18 years ago
That's just a reasonable value, I don't think that anybody out there will ever cascade more than 3 levels of constants;
this is possible now:
TEST4 = Kaviar TEST3 = Bananen, aber keinen {$TEST4} TEST1 = Affen {$TEST2} TEST2 = essen gerne {$TEST3}
this will output
Affen essen gerne Bananen, aber keinen {$TEST4}
We can easily increase to let's say 5 as the loop will end if there's no further substitution possible anyway...
btw: prior to this patch the following is not possible:
TEST2 = Test TEST1 = das ist ein {$TEST2}
this will output
das ist ein {$TEST2}
while this:
TEST1 = das ist ein {$TEST2} TEST2 = Test
gives the correct result:
das ist ein Test
so this "issue" is gone now too!
Updated by Wolfgang Klinger over 18 years ago
@hkdennis2k:
------------------------- abc=abc useabc={$abc} abc=def page.500 = TEXT page.500.value = {$useabc} Output: def ------------------------- x=x y=y xyz={$x}{$y}{$z} z=z page.500 = TEXT page.500.value = {$xyz} Output: xyz ------------------------- inner=inner inner2=inner2 outer={${$inner}2} page.500 = TEXT page.500.value = {$outer} Output: {${$inner}2} -------------------------
so the last one will not work (and did not before)
Updated by Michael Stucki over 18 years ago
I suggest you set the loop limit to 99 then so we will definitely never have any problems.
Please commit the patch to CVS so it is fixed there, but send a copy of the patch to the core list for information.
Thanks for providing a solution so quickly!
Updated by Wolfgang Klinger over 18 years ago
fixed in CVS, please update,
I set the limit to 10, that should really be enough and make no problems if there's a hidden recursion somewhere
(e.g.
TEST2 = Hello {$TEST2})