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> |