I recently had to take a string with some delimited values as placeholders and replace them with variables from an array. This is useful for things like sending out email newsletters or SMS messages with people’s names or other unique information in each message.

An example of a string with placeholders in it, using the string ‘%%’ as a delimeter is:

Hello %%NAME%%, your %%CAR%% is ready to pickup from %%STORE%%

Now take an array with some key/value pairs:

$filter = array('NAME'  => 'Iain Dooley',
                'CAR'   => 'Honda',
                'STORE' => 'Collingwood');

The following code will perform the replacement based on the filter:

<?php
    $delimited = 'Hello %%NAME%%, your %%CAR%% is ready to pickup from %%STORE%%';
    $delim = '%%';
    $matches = array();
    $pattern = '~'.$delim.'(.*?)'.$delim.'~';

    echo($pattern.PHP_EOL);

    $filter = new MyFilter();
    die(preg_replace_callback($pattern,array($filter,'findFilter'),$delimited));

    class MyFilter
    {   
        private $filter;

        public function MyFilter()
        {   
            $this->filter = array('NAME'  => 'Iain Dooley',
                                  'CAR'   => 'Honda',
                                  'STORE' => 'Collingwood');
        }

        function findFilter($arg)
        {   
            return $this->filter[$arg[1]];
        }
    }

The interesting parts of the above code are, in the pattern:

$pattern = '~'.$delim.'(.*?)'.$delim.'~';

the “?” makes this a “non-greedy” match, meaning that it won’t match everything in between the first and last occurence of $delim. Using “?” in this way allows you to make individual matches non-greedy. You can also use the /U modifier at the end of the expression to make all matches non greedy:

$pattern = '~'.$delim.'(.*)'.$delim.'~U';

The next interesting bit is the fact that the second argument to preg_replace_callback can be an array with an object and a method. This allows you to use preg_replace_callback in your OO based PHP application without breaking out into procedural code (cos where would you put it!?).