string.Format() in PHP[source]
xml
<glacius:metadata> | |
<title>string.Format() in PHP</title> | |
<description>Implementation of .NET-style string.Format() in PHP</description> | |
<category>PHP</category> | |
<category>C#</category> | |
<category>Programming</category> | |
<category>Legacy blog posts</category> | |
</glacius:metadata> | |
<glacius:macro name="legacy blargh banner"> | |
<properties> | |
<originalUrl>https://tmont.com/blargh/2010/1/string-format-in-php</originalUrl> | |
<originalDate>2010-01-09T22:22:08.000Z</originalDate> | |
</properties> | |
</glacius:macro> | |
<p> | |
.NET's <a href="https://www.php.net/sprintf"><code>sprintf()</code></a> | |
<a href="https://docs.microsoft.com/en-us/dotnet/api/system.string.format?view=net-6.0">equivalent</a> | |
has ordered parameters. | |
</p> | |
<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; | |
}]]></glacius:code> | |
<p> | |
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: | |
</p> | |
<ul> | |
<li> | |
The <a href="https://www.php.net/manual/en/pcre.constants.php#constant.preg-offset-capture"><code>PREG_OFFSET_CAPTURE</code></a> | |
constant tells the regex engine to capture the string index offset of each match. | |
</li> | |
<li> | |
<code>(?=\{)</code> and <code>(?!\})</code> in the regular expression are | |
<a href="https://www.regular-expressions.info/lookaround.html">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#). | |
</li> | |
<li> | |
<a href="https://www.php.net/manual/en/function.substr-replace.php"><code>substr_replace</code></a> is | |
an infrequently used, extremely useful function, that replaces a substring within a string, | |
expanding to the given width. | |
</li> | |
<li> | |
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. | |
</li> | |
</ul> |