eval 函数的替代方案是什么?

问题描述 投票:0回答:6

我在当前的项目中使用

eval()
,如下所示:

if (class_exists($class_name)) //$class_name depends on user input
    eval($class_name.'::MyStaticMethod()');
当且仅当名称为

eval()

 的类存在时,才会执行 
$class_name
,所以它有点安全,但我仍然不认为这是最好的解决方案。

如果没有

eval()
,我可以做与上面代码相同的事情吗?

php eval
6个回答
18
投票

我最近回答了这个问题我的答案的最后一部分完美地回答了这个问题,对于未来的读者来说比这里提供的答案更有用。这就是为什么我要回答我自己的问题。

PHP 的功能可以在大多数情况下避免使用

eval

  1. PHP 是非常动态的语言。它能够使用

    strings
    执行以下操作:

    • 定义和/或获取变量(从 PHP 4.3 开始支持)。例如:

      $variableName = 'MyVariable';
      // Create new variable with the name defined in variable $variableName
      ${$variableName} = 'MyValue';
      //Outputs: string(7) "MyValue"
      var_dump($MyVariable);
      //Outputs: string(7) "MyValue"
      var_dump(${'MyVariable'});
      

      演示

    • 调用函数(从PHP 4.3开始支持)。例如:

      // Create function with the name defined in variable $functionName
      function MyFunction($argument) {
          return 'Argument passed is: '.$argument;
      }
      
      $functionName = 'MyFunction';
      
      // Outputs:
      // string(48) "Argument passed is: Calling MyFunction directly."
      var_dump(MyFunction('Calling MyFunction directly.'));
      // Outputs:
      // string(51) "Argument passed is: Calling MyFunction with string."
      var_dump($functionName('Calling MyFunction with string.'));
      

      演示

    • 创建类的实例(从 PHP 5.0 开始支持)。例如:

      class MyClass {
          public function __construct() {
              echo 'Constructing MyClass'."\n";
          }
      }
      
      $className = 'MyClass';
      
      $objFromString = new $className();
      // Outputs: object(MyClass)#1 (0) {}
      var_dump($objFromString);
      

      演示

    • 调用静态方法(从PHP 5.0开始支持)。例如:

      class MyClass {
          public static function staticMethod() {
              return 'MyClass::staticMethod called';
          }
      }
      
      $staticMethodName = 'staticMethod';
      // Outputs: string(28) "MyClass::staticMethod called"
      var_dump(MyClass::$staticMethodName());
      

      演示

      从 PHP 5.3 开始,类名也可以通过字符串来定义。示例:

      class MyClass {
          public static function staticMethod() {
          return 'MyClass::staticMethod called';
          }
      }
      
      $className = 'MyClass';
      $staticMethodName = 'staticMethod';
      
      var_dump($className::$staticMethodName());
      var_dump($className::staticMethod());
      

      演示

    • 调用对象的实例方法(从PHP 5.0开始支持)。例如:

      class MyClass {
          public function instanceMethod() {
              return 'MyClass::instanceMethod called';
          }
      }
      
      $methodName = 'instanceMethod';
      
      $obj = new MyClass();
      // Outputs: string(30) "MyClass::instanceMethod called"
      var_dump($obj->$methodName());
      

      演示

    • 访问对象的静态和实例属性(从 PHP 5.0 开始支持)。例如:

      class MyClass {
          public static $myStaticProperty;
          public $myInstanceProperty;
      }
      
      $staticPropertyName = 'myStaticProperty';
      $instancePropertyName = 'myInstanceProperty';
      
      MyClass::${$staticPropertyName} = 'my static value';
      $obj = new MyClass();
      $obj->{$instancePropertyName} = 'my instance value';
      
      var_dump(MyClass::${$staticPropertyName});
      var_dump($obj->{$instancePropertyName});
      

      演示

  2. PHP 有两个函数:
    call_user_func
    call_user_func_array
    ,用于动态函数/方法调用。两者都有完整的文档记录,因此我不会在这里详细介绍。
  3. 即使以上一切还不够,PHP 5 还提供了很棒的
    Reflection
    API
    。不幸的是,文档中的示例很少,但反射是一个相当大的主题,需要在这里讨论。基本上,在阅读了反射的工作原理之后,使用反射并不是什么大不了的事。

6
投票

我建议

call_user_func

call_user_func()
的替代方法是这样称呼它:

$class_and_method = 'Class::MyStaticMethod()';
$class_and_method();

5
投票

是的:

call_user_func(array($class_name, 'MyStaticMethod'));

3
投票

从 PHP 5.3+ 开始,

$class_name::MyStaticMethod();

1
投票

艾迪索里: 用户输入+评估=安全漏洞;

eval 也是一项昂贵的操作,需要将字符串解析为可操作的格式(解析树、抽象语法树等)并执行新找到的逻辑。

您不想评估代码的每一个小细节。如果您有东西可以咀嚼,或者更确切地说将该逻辑放在可重用和参数化的地方(例如函数),请使用 eval。

也从 php 5.4 开始

$method = array('class_name', 'method_name');
$method(); // calls class_name::method_name()

0
投票

加载后评估一些 PHP 代码。

我们可以使用

proc_open
并将一些PHP输入到
STDIN
中。

为了避免 shell 和 Unicode 字符出现任何问题,传入以

base64
编码的字符串会更安全。

请注意,PHP 取决于 php-cli .ini 设置。

function run($php){
  $php = base64_encode($php);
  $proc = proc_open("echo '$php' | base64 --decode | php",
    [["pipe","r"],["pipe","w"],["pipe","w"]],
    $pipes
  );
  print stream_get_contents($pipes[1]);
}

echo run("Hi <?php echo getenv()['USER'];?>! 😃\n");
// Hi NVRM! 😃

https://www.php.net/manual/en/function.proc-open.php

© www.soinside.com 2019 - 2024. All rights reserved.