PHP format() function with named placeholders

Goal

Format a string by merging it with provided values using named placeholders.

Instead of writing a string with %s placeholders using PHP's printf() and having to line up the values in order in an array, I would like to have named placeholders for clarity, just like if it was a Smarty-like template, and feed it an associative array for values.

Using %s placeholders

$string = <<<SQL
CREATE DATABASE IF NOT EXISTS %s;
GRANT ALL PRIVILEGES ON %s.* TO '%s'@'%s';
SET PASSWORD = PASSWORD('%s');
SQL;
$args = ["people", "people", "staff", "localhost", "asdf123"];
vprintf($string, $args);
printf($string, ...$args);
echo vsprintf($string, $args);
echo sprintf($string, ...$args);

Result:

CREATE DATABASE IF NOT EXISTS people;
GRANT ALL PRIVILEGES ON people.* TO 'staff'@'localhost';
SET PASSWORD = PASSWORD('asdf123');

Using named placeholders

I would prefer doing this:

$string = <<<SQL
CREATE DATABASE IF NOT EXISTS {{database}};
GRANT ALL PRIVILEGES ON {{database}}.* TO '{{user}}'@'{{host}}';
SET PASSWORD = PASSWORD('{{pass}}');
SQL;
$kwargs = ["database"=>"people", "user"=>"staff", "pass"=>"asdf123", "host"=>"localhost"];
echo format($string, $kwargs);

Advantages

  • No need for duplicate values.
  • Values don't have to be ordered.

Ruby's format() with named placeholders

https://docs.ruby-lang.org/en/2.5.0/Kernel.html#method-i-format

puts format("Coordinates: %{latitude}, %{longitude}", latitude: '37.24N', longitude: '-115.81W')
kwargs = {latitude: '37.24N', longitude: '-115.81W'}
puts format("Coordinates: %{latitude}, %{longitude}", **kwargs)

Result:

Coordinates: 37.24N, -115.81W

Python's format() with named placeholders

https://docs.python.org/3.5/library/string.html#format-examples

print 'Coordinates: {latitude}, {longitude}'.format(latitude='37.24N', longitude='-115.81W')
kwargs = {'latitude': '37.24N', 'longitude': '-115.81W'}
print 'Coordinates: {latitude}, {longitude}'.format(**kwargs)

Result:

Coordinates: 37.24N, -115.81W

PHP's format() with named placeholders

<?php
function format($string, array $kwargs, $pattern='/\{\{(\w+)\}\}/') {
    return preg_replace_callback($pattern, function ($matches) use ($kwargs) {
        return @$kwargs[$matches[1]] ?: $matches[0];
    }, $string);
}
echo format("Coordinates: {{latitude}}, {{longitude}}", ['latitude'=>'37.24N', 'longitude'=>'-115.81W']);

Try with Ruby-like %{} placeholders by changing the regex pattern (the 3rd function argument).

echo format("Coordinates: %{latitude}, %{longitude}", ['latitude'=>'37.24N', 'longitude'=>'-115.81W'], '/\%\{(\w+)\}/');

Try with Ruby-like symbol placeholders by changing the regex pattern.

echo format("Coordinates: :latitude, :longitude", ['latitude'=>'37.24N', 'longitude'=>'-115.81W'], '/:(\w+)/');

Try with Python-like single curly bracket placeholders by changing the regex pattern.

echo format("Coordinates: {latitude}, {longitude}", ['latitude'=>'37.24N', 'longitude'=>'-115.81W'], '/\{(\w+)\}/');

Result:

Coordinates: 37.24N, -115.81W

Missing value or placeholder key doesn't exist in kwargs:

echo format("Coordinates: {{latitude}}, {{longitude}}, {{timezone}}", ['latitude'=>'37.24N', 'longitude'=>'-115.81W']);

Result:

Coordinates: 37.24N, -115.81W, {{timezone}}