28

Let's say my string is:

$str = "abcdefg foo() hijklmopqrst";

How do I let PHP call the function foo() and insert the returning string to the rest of that string?

2
  • Is there a particular reason why this question is not interested in sprintf()? Commented Sep 3 at 7:00
  • I mean, everybody here tried to answer on-topic, but this is causing nightmare answers loool - I mean: one answer implemented its own regex parser (slow, security nightmare), another uses global variables (dirty hack), another one global classes and methods (dirty hack), another just does string concatenation (efficient hack). Basically they are generating crazy answers lol but sprintf("abcdefg %s hijklmopqrst", foo()) is really maybe something that may cover your original use-case (?) but it's not really what is asked here. Thanks for this small late clarification Commented Sep 3 at 7:32

8 Answers 8

35

If you're calling a method of some class, you can use normal variable expansion. For example:

<?php
class thingie {

  public function sayHello() {
    return "hello";
  }

}

$t = new thingie();
echo "thingie says: {$t->sayHello()}";

This will output:

thingie says: hello

Note that the braces around the call are required.

Sign up to request clarification or add additional context in comments.

2 Comments

But it seems calling a global function this way, won't work
By wrapping the global functions you want to support in an object of methods, you can control the footprint of exposure to bugs and security leaks. I think you'd be hard-pressed to find an easier way to /safely/ offer such power. Your wrapper methods can even perform additional validation/restriction if needed.
25
function foo()
{
    return 'Hi';
}
$my_foo = 'foo';
echo "{$my_foo()}";

1 Comment

This is a great "trick." You can even pass parameters or other variables to it, ie. echo "{$my_foo('bar')}" or echo "{$my_foo($bar)}" - especially useful when building SQL queries with many escaped values.
24

Just use this:

$str = "abcdefg".foo()."hijklmnopqrstuvwxyz";

It will call function during string creation.

1 Comment

This isn't string interpolation.
12
$foo = foo();
$str = "abcdefg {$foo} hijklmopqrst";

Comments

11
$str="abcdefg foo() hijklmopqrst";
function foo() {return "bar";}

$replaced = preg_replace_callback("~([a-z]+)\(\)~", 
     function ($m){
          return $m[1]();
     }, $str);

output:

$replaced == 'abcdefg bar hijklmopqrst';

This will allow any lower-case letters as function name. If you need any other symbols, add them to the pattern, i.e. [a-zA-Z_].

Be VERY careful which functions you allow to be called. You should at least check if $m[1] contains a whitelisted function to not allow remote code injection attacks.

$allowedFunctions = array("foo", "bar" /*, ...*/);

$replaced = preg_replace_callback("~([a-z]+)\(\)~", 
     function ($m) use ($allowedFunctions) {
          if (!in_array($m[1], $allowedFunctions))
              return $m[0]; // Don't replace and maybe add some errors.

          return $m[1]();
     }, $str);

Testrun on "abcdefg foo() bat() hijklmopqrst" outputs "abcdefg bar bat() hijklmopqrst".

Optimisation for whitelisting approach (building pattern dynamically from allowed function names, i.e. (foo|bar).

$allowedFunctions = array("foo", "bar");

$replaced = preg_replace_callback("~(".implode("|",$allowedFunctions).")\(\)~", 
     function ($m) {
          return $m[1]();
     }, $str);

1 Comment

What if the function has parameters?
9

Short answer: No.

No. There is no such native construct to call functions like "Date is: date() yeah yeah" and processing such string sounds like a performance nightmare, and a security nightmare.

Good news: you may really just use printf() or sprintf():

<?php
printf(
    'Year is: %s, and month is: %s',
    date('Y'),
    date('m')
);

Output:

Year is: 2025, and month is: 09

Documentation about printf:

https://www.php.net/sprintf

Long answer: Well... Yes. There is This Hack

Well. Yes. If you really need to get arbitrary expressions being evaluated from a double-quoted string, you can implement a workaround, speculating on a feature called variable-functions:

<?php
/**
 * Hack to dynamically process things inside strings.
 *
 * @param mixed $v Value
 * return mixed Same value
 */
$GLOBALS['_'] = function ($v) {
    return $v;
};


// Happy hacking in global context
echo "Year is: {$_(date('Y'))} and the max function returns {$_(max( 1, 2, 3 ))}...{$_(str_repeat(' arrh', 3))}! ";

// Happy hacking inside functions
function test() {
    global $_;
    echo "Also works in functions! Here random: {$_(random_int(0, 10))}. Yeah!";
}
test();

Result:

Year is 2025 and the max function returns 3... arrh arrh arrh!
Also works in functions! Here random: 8. Yeah!

The example is not limited to date(), max() and str_repeat(): you can surely define your own functions like foo() and just call them, as long as they return a valid string.

This example creates a simple global variable called just $_ and this name is adopted just to be very very short, so you type less. This variable contains a simple function which just returns the first argument. This is syntax sugar for you, since functions are not easily expanded as-is inside a string. Instead, variables are expanded easily. That's it.

I wonder if PHP will ever introduce a native feature to do that (note: I've written this note in 2018). In the meanwhile, this is the only workaround.

References:

Limitations of This Hack

Note that, with this hack, the functions are immediately expanded when you define the string. So, do not expect to store the string in a variable and see the result changed every time you print it.

Another reason why you should not use this hack, is that it's not compatible with many internationalization workflows. For example it's not compatible with GNU Gettext.

2 Comments

5

Its still not possible, There are hacks available but not what I would recommend rather suggest to stick with old school dot operator i.e. $str="abcdefg ". foo() ." hijklmopqrst";

As per the Complex (curly) syntax documentation

Note:
Functions, method calls, static class variables, and class constants inside {$} work since PHP 5. However, the value accessed will be interpreted as the name of a variable in the scope in which the string is defined. Using single curly braces ({}) will not work for accessing the return values of functions or methods or the values of class constants or static class variables.

Comments

-1
<? 
function foo($b)
{
    return "Hi $b";
}
$bar = 'bario';


$my_foo = 'foo';
echo "<br>1 {$my_foo($bar)}"; 

$myfoo = foo; // my 'version'
echo "<br>2 {$myfoo($bar)}"; 

// the following is nogo; php error! $myfoo can not be called as function because it got the return value if foo() which is a string.
// means https://stackoverflow.com/users/517676/savinger answer above is wrong; this program doesn't print "<br>end":
 
$myfoo = foo();
echo "<br>3 {$myfoo($bar)}"; 

echo "<br>end";
?>

The output is:

1 Hi bario
2 Hi bario

6 Comments

$myfoo = foo; is not "your" version but a PHP error. The only working solution is the first one and it's already provided. This answer has zero value.
great comment YCS, but note, 1st, i wrote // my 'version' not // 'my' version. which should make clear that it was meant ironically--though it even works. 2nd, that it works due to a php error is not in my responsability. 3rd, both ways are a bad hack and not a solution. 4th, the value i added and which was the reason for my post was to point out that a previous 'solution' (savinger) remained uncriticized --to the contrary, he got 10 upvotes!--, but to which i couldn't comment due to having not enough reputations, so i chose to answer instead.
"it even works" - where I live, it doesn't. "was the reason for my post was to point out that a previous 'solution' (savinger) remained uncriticized" - I fail to see any mention of it in your answer. And personally, I don't see any drawbacks in the savinger's solution which is clear and straightforward (and has nothing to do with any of your hacks which actually resemble that from v.babak's answer).
aha, i see, it depends on the php version. i still use php 5.5. mea culpa. it's the version that runs on my server. the output I gave for $myfoo = foo; echo "<br>2 {$myfoo($bar)}"; is authentic. I ran the example. whereas (repeat) savinger's 'solution' produces and error with php 5.5. I mentioned in my example // stackoverflow.com/users/517676/savinger
using $myfoo = foo; echo "<br>2 {$myfoo($bar)}"; on 3v4l.org; on my server i doesn't show the notice below: Output for 5.5.38 | released 2016-07-21 | took 23 ms, 16.83 MiB Notice: Use of undefined constant foo - assumed 'foo' in /in/gIIEX on line 9 <br>2 Hi bario
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.