Search code examples
phpregexslug

Improving speed of regex and using preg_replace for slugs


Previously I have been echoing $obj->html but a current project requires that the HTML be examined for slugs like {whatever} and replacing these with other content.

I have two problems. The first is that this code is slower than I would like:

class Foo {

  function draw_content() {
    $slug = "/(?<=\{).*(?=\})/";
    if (preg_match($slug, $this->html, $matches)) {
        foreach ($matches as $match) {
            if (method_exists($this,$match))    {
                $replacement = $this->$match();
                $this->html = preg_replace("/\{$match\}/", $replacement, $this->html);
            }
        }
    } 
    return $this->html;
 } // fn

  function new_releases() {
    echo "new release book covers"; 
  }  // fn

} // class

Is there a better way to get the slug contents? I presume the regex is what is slowing this down?

The second issue is stranger to me. Given this $obj->html:

<p class="headline">New Releases</p>
<p>xxx{new_releases}xxxx</p>

The processed output of $obj->draw_content() is drawn by <?=$obj->draw_content()?>

new release book covers<p class="headline">New Releases</p>
<p>xxxxxxx</p>

Why is the new_releases() output prepended? The slug is gone but the replacement is not in it's place!


Solution

  • you can replace your pattern by:

    $slug = '~{\K[^}]*+(?=})~';
    

    IMHO, you should replace your preg_match test and your preg_replace by an only preg_replace_callback function, try something like this (and correct the bugs :).

    function draw_content() {
        $slug = '~{([^}]*+)}~';
        $that = $this;
        $this->html = preg_replace_callback( $slug, function ($m) use ($that) {
            if (method_exists($that, $m[1]))
                return $that->$m[1]();
            return $m[0]; }, $this->html);
        return $this->html;
    }