string.Format() in PHP[source]

    <title>string.Format() in PHP</title>
    <description>Implementation of .NET-style string.Format() in PHP</description>
    <category>Legacy blog posts</category>
<glacius:macro name="legacy blargh banner">
  .NET's <a href=""><code>sprintf()</code></a> 
  <a href="">equivalent</a> 
  has ordered parameters.
<glacius:code lang="csharp"><![CDATA[var s = string.Format("My name is {1}, {0}", "John", "Doe");
//s = "My name is Doe, John"
var s = string.Format("My name is {{{0}}}", "John");
//s = "My name is {John}"]]></glacius:code>
<p>I needed that. Here it is, PHPified:</p>
<glacius:code lang="php"><![CDATA[function format($format) {
	$args = func_get_args();
	$format = array_shift($args);
	preg_match_all('/(?=\{)\{(\d+)\}(?!\})/', $format, $matches, PREG_OFFSET_CAPTURE);
	$offset = 0;
	foreach ($matches[1] as $data) {
		$i = $data[0];
		$format = substr_replace($format, @$args[$i], $offset + $data[1] - 1, 2 + strlen($i));
		$offset += strlen(@$args[$i]) - 2 - strlen($i);
	return $format;
  There's a lot going on in here that isn't used very often in PHP. Here is a terse 
  explanation of the not-so-obvious features:
    The <a href=""><code>PREG_OFFSET_CAPTURE</code></a> 
    constant tells the regex engine to capture the string index offset of each match.
    <code>(?=\{)</code> and <code>(?!\})</code> in the regular expression are 
    <a href="">positive and negative lookarounds</a>, 
    respectively. The nice thing about that is they're also zero-width matching, which means they 
    won't be returned as part of the match result. These are needed because to output a 
    literal <code>{</code> in a C# string you precede it with another <code>{</code> (a little known 
    fact about C#).
    <a href=""><code>substr_replace</code></a> is 
    an infrequently used, extremely useful function, that replaces a substring within a string, 
    expanding to the given width.
    The <code>$offset</code> variable tracks the string length delta. Since we're modifying the
    string, the offsets captured in the regex match becomes out of date.