16

Let's say string is:

$str="abcdefg foo() hijklmopqrst";

How do I let php call foo() and insert the returning string to this string?

Matthew Lock
  • 12,582
  • 11
  • 88
  • 124
lovespring
  • 18,247
  • 41
  • 98
  • 148

7 Answers7

29

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.

HonoredMule
  • 689
  • 12
  • 21
  • 2
    But it seems calling a global function this way, won't work – Opux Oct 31 '16 at 16:57
  • 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. – HonoredMule Jun 27 '18 at 13:57
20

Just use this:

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

It will call function during string creation.

Frederick Marcoux
  • 2,139
  • 1
  • 26
  • 56
14
function foo()
{
    return 'Hi';
}
$my_foo = 'foo';
echo "{$my_foo()}";
v.babak
  • 678
  • 9
  • 13
  • 3
    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. – Nick D May 24 '17 at 21:17
10
$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);
Basti
  • 4,000
  • 16
  • 20
7
$foo = foo();
$str = "abcdefg {$foo} hijklmopqrst";
savinger
  • 6,194
  • 9
  • 35
  • 57
5

To get arbitrary expressions being evaluated from a double-quoted string you can speculate on variable-functions:

<?php
// A user function
function foo() {
    return 'bar';
}

/**
 * The hack
 *
 * @param $v mixed Value
 * return mixed Value (untouched)
 */
$_ = function ( $v ) {
    return $v;
};

// Happy hacking
echo "Foo is {$_( foo() )} and the sum is {$_( 41 + 1 )}...{$_( str_repeat( ' arrh', 3 ) )}!";

Result:

Foo is bar and the sum is 42... arrrh arrrh arrrh!

References:

Valerio Bozz
  • 712
  • 11
  • 25
4

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.

Mubashar
  • 11,822
  • 11
  • 62
  • 95