Using preg_replace_callback
with a modern approach, we can even use a helper class library to support dot notation (adbario/php-dot-notation) inside out format along with array keys:
use \Adbar\Dot;
function format($text, ...$args)
{
$params = new Dot([]);
if (count($args) === 1 && is_array($args[0])) {
$params->setArray($args[0]);
} else {
$params->setArray($args);
}
return preg_replace_callback(
'/\{(.*?)\}/',
function ($matches) use ($params) {
return $params->get($matches[1], $matches[0]);
},
$text
);
}
And we can use it like this:
> format("content:{0} title:{0}^4.0 path.title:{0}^4.0 description:{0} ...", "Cheese");
"content:Cheese title:Cheese^4.0 path.title:Cheese^4.0 description:Cheese ..."
> format(
'My name is {name} and my age is {age} ({name}/{age})',
['name' => 'Christos', 'age' => 101]
);
"My name is Christos and my age is 101 (Christos/101)"
> format(
'My name is {name}, my age is {info.age} and my ID is {personal.data.id} ({name}/{info.age}/{personal.data.id})',
[
'name' => 'Chris',
'info' => [
'age' => 40
],
'personal' => [
'data' => [
'id' => '#id-1234'
]
]
]
);
"My name is Christos, my age is 101 and my ID is #id-1234 (Christos/101/#id-1234)"
Of course we can have a simple version without any extra libraries if we don't want multilevel array support using dot notation:
function format($text, ...$args)
{
$params = [];
if (count($args) === 1 && is_array($args[0])) {
$params = $args[0];
} else {
$params = $args;
}
return preg_replace_callback(
'/\{(.*?)\}/',
function ($matches) use ($params) {
if (isset($params[$matches[1]])) {
return $params[$matches[1]];
}
return $matches[0];
},
$text
);
}