12

Is there a way in PHP to name my specifiers like in Python?

I want this in PHP:

$foo = array('name' => 24);
printf("%(name)d", $foo);

I couldn't find nothing related on google or in the php manual.

Michael Berkowski
  • 267,341
  • 46
  • 444
  • 390
Paul
  • 20,883
  • 7
  • 57
  • 74

4 Answers4

12

Nice question!

You can roll your own without too much trouble by working with regexes. I based the implementation on the idea of calling vsprintf, which is closest to the stated goal among the built-in printf family of functions:

function vsprintf_named($format, $args) {
    $names = preg_match_all('/%\((.*?)\)/', $format, $matches, PREG_SET_ORDER);

    $values = array();
    foreach($matches as $match) {
        $values[] = $args[$match[1]];
    }

    $format = preg_replace('/%\((.*?)\)/', '%', $format);
    return vsprintf($format, $values);
}

To test:

$foo = array('age' => 5, 'name' => 'john');
echo vsprintf_named("%(name)s is %(age)02d", $foo);

Update: My initial implementation was very lambda-happy. Turns out a super basic foreach will suffice, which also makes the function usable in PHP >= 4.1 (not 100% sure about the specific version, but should be around there).

See it in action.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • 1
    Nice answer! I wonder if it could be made run faster by not using any regex. – kgilden Sep 15 '11 at 18:27
  • 1
    @gilden: That's a non-issue or, if you prefer, a dangerous path to premature optimization. Is your app going to be CPU-bound formatting strings all day long? – Jon Sep 15 '11 at 18:28
  • Of course not, I'm just curious if it makes any difference. I'm guessing not by a margin high enough to consider doing it. – kgilden Sep 15 '11 at 18:30
  • `echo vsprintf()` is an "antipattern". There is absolutely no reason that anyone should ever write `echo vsprintf()` in any code for any reason -- it should be `vprintf()` every time. Also I recommend a negated character class `[^)]` with a greedy quantifier instead of lazy matching with a dot. – mickmackusa Apr 08 '22 at 05:47
9

Use strtr:

$foo = array('%name%' => 24);
strtr("%name%", $foo); // 24

You could also do this:

"${foo['name']}"

Or this:

$name = 24;
"$name"
Arnaud Le Blanc
  • 98,321
  • 23
  • 206
  • 194
  • But this discards the other features of `printf()` like padding, number formatting, etc. – Michael Berkowski Sep 15 '11 at 17:55
  • @MichaelBerkowski OP does not mention anything about other features, at least not clearly (the python code). Considering that, `strstr` is PHP function which lets you define your own specifiers. At least that was what I was looking for and google ushered me here. – ruuter Jul 17 '15 at 12:04
  • Nice. Strtr is the way. If you want also sprintf features, use it together: sprintf(strtr($str, $trans), ...) – Marco Marsala Aug 18 '15 at 10:41
  • `strtr()` does not modify by reference. This answer would benefit from some explanation and coding improvement so that it doesn't confuse researchers. – mickmackusa Apr 08 '22 at 05:46
9

You can do it with sprintf by numbering the parameters, like so:

echo sprintf('hello, %2$s. What is your %1$s', 'age', 'Jesse');


Outputs the following string:

hello, Jesse. What is your age

Jesse Bunch
  • 6,651
  • 4
  • 36
  • 59
  • 12
    He probably meant that you can skip echo if you'd use printf instead. – uKolka Jan 06 '14 at 17:21
  • `echo sprintf()` is an "antipattern". There is absolutely no reason that anyone should ever write `echo sprintf()` in any code for any reason -- it should be `printf()` every time. – mickmackusa Apr 08 '22 at 05:45
0

the closer core function is vsprintf() to use an array instead of multiple parameter, but you still have to use numbered parameters.

in the comments of this function docs there is someone who created a function to do what you want vnsprintf() printf+array+named parameters

Einacio
  • 3,502
  • 1
  • 17
  • 21