【问题标题】:In PHP, How to call a function interpolated in string?在 PHP 中,如何调用插入字符串的函数?
【发布时间】:2012-04-17 15:52:13
【问题描述】:

假设字符串是:

$str="abcdefg foo() hijklmopqrst";

如何让 php 调用 foo() 并将返回的字符串插入到这个字符串中?

【问题讨论】:

  • 非常不愉快。您是否有要允许此功能的功能列表,或任何一般功能? (另外,您已经考虑过这对安全性和性能的影响,是吗?)
  • 您可以使用 eval() 但不广泛推荐。
  • 请向我们提供有关您的代码的更多信息。这个字符串是从哪里来的?你提到了一个 API?
  • 请不要将已回答的问题更改为另一个问题。改为打开一个新问题。

标签: php


【解决方案1】:

这仍然不可能,有一些可用的技巧,但不是我建议的,而是建议坚持使用老式点运算符,即$str="abcdefg ". foo() ." hijklmopqrst";

根据Complex (curly) syntax documentation

注意:
{$} 中的函数、方法调用、静态类变量和类常量从 PHP 5 开始工作。但是,访问的值将被解释为定义字符串的范围内的变量的名称。使用单个花括号 ({}) 无法访问函数或方法的返回值或类常量或静态类变量的值。

【讨论】:

    【解决方案2】:

    要从双引号字符串中获取任意表达式,您可以推测变量函数:

    <?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 ) )}!";
    

    结果:

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

    参考资料:

    【讨论】:

      【解决方案3】:
      function foo()
      {
          return 'Hi';
      }
      $my_foo = 'foo';
      echo "{$my_foo()}";
      

      【讨论】:

      • 这是一个很棒的“技巧”。您甚至可以将参数或其他变量传递给它,即。 echo "{$my_foo('bar')}"echo "{$my_foo($bar)}" - 在构建带有许多转义值的 SQL 查询时特别有用。
      【解决方案4】:

      如果你正在调用某个类的方法,你可以使用普通的变量扩展。例如:

      <?php
      class thingie {
      
        public function sayHello() {
          return "hello";
        }
      
      }
      
      $t = new thingie();
      echo "thingie says: {$t->sayHello()}";
      

      这将输出:

      thingie 说:你好

      请注意,调用周围的大括号必需的。

      【讨论】:

      • 但是这样调用全局函数好像不行
      • 通过将要支持的全局函数包装在方法对象中,您可以控制暴露于错误和安全漏洞的足迹。我认为你很难找到一种更简单的方法来/安全地/提供这种权力。如果需要,您的包装器方法甚至可以执行额外的验证/限制。
      【解决方案5】:
      $str="abcdefg foo() hijklmopqrst";
      function foo() {return "bar";}
      
      $replaced = preg_replace_callback("~([a-z]+)\(\)~", 
           function ($m){
                return $m[1]();
           }, $str);
      

      输出:

      $replaced == 'abcdefg bar hijklmopqrst';
      

      这将允许任何小写字母作为函数名。如果您需要任何其他符号,请将它们添加到模式中,即[a-zA-Z_]

      非常小心您允许调用的函数。您至少应该检查 $m[1] 是否包含列入白名单的函数以不允许远程代码注入攻击。

      $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);
      

      "abcdefg foo() bat() hijklmopqrst" 上测试运行输出"abcdefg bar bat() hijklmopqrst"

      优化白名单方法(从允许的函数名称动态构建模式,即(foo|bar)

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

      【讨论】:

      • 函数有参数怎么办?
      【解决方案6】:

      就用这个吧:

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

      它会在字符串创建过程中调用函数。

      【讨论】:

      • 你要使用什么功能?
      • @lovespring 这是一个可怕的设置。您使用什么 API 可以做到这一点?
      • 我可以调用但不能修改其他人的代码,他没有给我API,我必须挂钩$str来注入我的代码。
      【解决方案7】:
      $foo = foo();
      $str = "abcdefg {$foo} hijklmopqrst";
      

      【讨论】:

      • 我必须在 $str 时间调用 foo()。
      • @lovespring 你的意思是以后的某个时间点?也许您正在寻找eval($str)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-04-07
      • 2019-10-30
      • 1970-01-01
      • 2019-12-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多