I am getting PREG_JIT_STACKLIMIT_ERROR error in preg_replace_callback() function when working with a bit longer string. Above 2000 characters it is not woking (
The problem as you can see is that your pattern is inefficient. The main reasons are:
(a+)+b that is the best way for a catastrophic backtracking(a|b)+ that may be a good design except for a backtracking regex engine like pcreAs an aside, there are too much useless capture groups that consumes memory for nothing. When you don't need a capture group, don't write it. If you really need to group elements, use a non-capturing group, but don't use non-capturing groups to make a pattern "more readable" (there are other ways to do that like named groups, free-spacing and comments).
If I understand well, you are trying to build a regex for preg_replace_callback to deal with the control statement of your template system.
Since these control statements can be nested and a regex engine can't match several times the same substring, you have to choose between several strategies:
You can write a recursive pattern to describe a conditional statement that eventually contains other conditional statements.
You can write a pattern that matches only the innermost conditional statements. (In other words it forbids nested conditional statements.)
In the two cases, you need to parse the string several times until there's nothing to replace. (Note that you can also use a recursive function with the first strategy, but it makes things more complicated.)
Let's see the second way:
$pattern = '~
{@ (? \w+ ) - (? \w+ (?: % \w+ )* ) (?: : (? \w+ ) )? \|
# a "THEN" part that doesn\'t have nested conditional statements
(? [^{|@]*+ (?: { (?!@) [^{|@]* | @ (?!}) [^{|@]* )*+ )
# optional "ELSE" part (the content is similar to the "THEN" part)
(?: \| (? \g ) )? (*SKIP) @}~x';
$parsed_view = $string;
$count = 0;
do {
$parsed_view = preg_replace_callback($pattern, function ($m) {
// do what you need here. The different captures can be
// easily accessed with their names: $m['cond'], $m['stat']...
// as defined in the pattern.
return $result;
}, $parsed_view, -1, $count);
} while ($count);
pattern demo
As you can see the problem of nested statements is solved with the do..while loop and the count parameter of preg_replace_callback to see if something is replaced.
This code isn't tested, but I'm sure you can complete it and eventually adapt it to your needs.
As an aside, there's a lot of template engines that already exists (and PHP is already a template engine). You can use them and avoid to create your own syntax. You can also take a look at their codes.