我听说many places PHP的eval
函数是often not the answer。鉴于PHP 5.3的LSB和closures,我们已经没有理由依赖eval
或create_function
。
是否有任何可以想象的情况,其中eval
是PHP 5.3中最好的(仅?)答案?
这个问题不关于eval
是否一般是邪恶的,因为它显然不是。
答案摘要:
var_export
答案 0 :(得分:18)
如果您正在编写恶意软件,并且您想为那些试图在您之后进行清理的系统管理员努力工作。根据我的经验,这似乎是最常见的用例。
答案 1 :(得分:17)
Eric Lippert总结了三篇博文。这是一个非常有趣的阅读。
据我所知,以下是使用eval的一些唯一原因。
例如,当您根据用户输入构建复杂的数学表达式时,或者将对象状态序列化为字符串以便可以存储或传输它,并在以后重构时。
答案 2 :(得分:8)
eval
的主要问题是它是恶意代码的网关。因此,你永远不应该在可以从外部利用它的环境中使用它,例如用户提供了输入。
一个有效的UseCase将在Mocking Frameworks中。
来自PHPUnit_Framework_TestCase::getMock()
// ... some code before
$mock = PHPUnit_Framework_MockObject_Generator::generate(
$originalClassName,
$methods,
$mockClassName,
$callOriginalClone,
$callAutoload
);
if (!class_exists($mock['mockClassName'], FALSE)) {
eval($mock['code']);
}
// ... some code after
生成方法实际上发生了很多事情。在外行术语中:PHPUnit将参数generate
并从中创建一个类模板。然后它将eval
该类模板使其可用于实例化。关键是让TestDoubles在UnitTests中模拟依赖关系。
答案 3 :(得分:5)
您可以使用eval创建临时类:
function myAutoLoad($sClassName){
# classic part
if (file_exists($sClassName.'.php'){
require $sClassName.'.php';
} else {
eval("
class $sClassName{
public function __call($sMethod,$aArgs){
return 'No such class: ' . $sClassName;
}
}");
}
}
虽然,当然,使用非常有限(一些API或者可能是DI容器,测试框架,ORM必须处理具有动态结构的数据库,代码游乐场)
答案 4 :(得分:3)
如果您正在编写一个解释和执行PHP代码的站点,就像交互式shell一样。
...
我是一个系统人,这就是我得到的。
答案 5 :(得分:3)
eval
是一个可用于检查语法错误的构造。
假设您有这两个PHP脚本:
script1.php
<?php
// This is a valid syntax
$a = 1;
script2.php
<?php
// This is an invalid syntax
$a = abcdef
您可以使用eval
检查语法错误:
$code1 = 'return true; ?>'.file_get_contents('script1.php');
$code2 = 'return true; ?>'.file_get_contents('script2.php');
echo eval($code1) ? 'script1 has valid syntax' : 'script1 has syntax errors';
echo eval($code2) ? 'script2 has valid syntax' : 'script2 has syntax errors';
与php_check_syntax(不管怎样已弃用和删除)不同,代码不会被执行。
编辑:
另一个(首选)替代方案为php -l
。如果您无权访问system()或shell执行命令,则可以使用上述解决方案。
此方法可以在代码中注入类/函数。在执行此操作之前,请务必执行preg_replace
调用或namespace
,以防止在后续调用中执行这些调用。
关于OP主题:何时(如果有的话)是eval而不是邪恶? eval
根本就不是邪恶的。程序员无缘无故地使用eval
是邪恶的。 eval
可缩短您的代码(数学表达式评估,每个示例)。
答案 6 :(得分:2)
我发现有时语言的大多数功能都很有用。毕竟,即使是GOTO
has had its proponents。 Eval用于许多框架中,并且使用得很好。例如,CodeIgniter使用eval
来区分PHP 4的类层次结构和PHP 5实现。允许执行PHP代码的博客插件肯定需要它(这是Expression Engine,Wordpress等中可用的功能)。我也将它用于一个网站,其中一系列视图几乎相同,但每个都需要自定义代码,并且创建某种疯狂的规则引擎要复杂得多且速度慢。
虽然我知道这不是PHP,但我发现Python的eval使得基本计算器的实现变得更加简单。
基本上,这是问题:
eval
(或变量变量,或任何其他形式的字符串查找或反射语法),则可能有另一种方法。你有其他选择吗?你有一个合理限制的输入集吗?可以使用switch语句吗?其他考虑因素:
答案 7 :(得分:1)
适当的场合(假设没有简单的替代方案)将是使用var_export
序列化可信数据并且必须对其进行反序列化。当然,它永远不应该以这种方式序列化,但有时错误已经完成。
答案 8 :(得分:1)
我想,应该在代码实际需要编译的地方使用eval。我的意思是像模板文件编译(为了性能而进入PHP的模板语言),插件钩子编译,出于性能原因的编译等等。
答案 9 :(得分:1)
您可以使用eval创建安装系统后添加代码的设置。通常,如果您想要更改服务器上的代码,则必须添加/更改现有的PHP文件。另一种方法是将代码存储在数据库中并使用eval来执行它。你必须确保添加的代码是安全的。
把它想象成一个插件,只是一个可以做任何事情的插件......
你可以想到一个允许人们贡献代码片段的网站,然后用户可以动态地将这些代码片段添加到他们的网页中 - 而这些代码片段实际上不会在Web服务器文件系统上保存代码。您需要的是审批流程......
答案 10 :(得分:0)
<强>兼容性即可。提供PHP4后备是非常频繁的。但同样,可能希望在5.3中模拟PHP5.4功能,例如SplString
。虽然只是提供两个包含变体(include.php4与include.php5)很常见,但有时候使用eval()更有效或可读:
$IMPL_AA = PHP_VERSION >= 5 ? "implements ArrayAccess" : "";
eval(<<<END
class BaseFeature $IMPL_AA {
在这种情况下,代码将在PHP4上工作,但仅在PHP5上公开更好的API /语法。请注意,该示例是虚构的。
答案 11 :(得分:0)
当我有一个与我沟通的php引擎机器人时,我使用了eval,我可以告诉它通过EVAL: php commands here
执行命令。仍然是邪恶的,但如果你的代码不知道会发生什么(如果你从数据库中提取一大块PHP代码),eval是唯一的解决方案。
答案 12 :(得分:0)
因此,对于所有使用eval
的语言都应该如此:
基本上,除了少数例外情况,如果您正在构建传递给eval
的值或从非战斗源获取它,那么您做错了。如果你在静态字符串上调用eval,情况也是如此。
除了在运行时初始化解析器的性能问题以及安全问题之外,您通常会使用类型系统。
更严重的是,已经证明,在绝大多数情况下,解决方案有更优雅的方法。但是,不要直接禁止构造,而是将其视为goto
可能很好。两者都有合法用途,但这是一个很好的红旗,如果你正在以正确的方式解决问题,应该让你思考。
根据我的经验,我只找到了属于插件类别和特权用户(例如,网站管理员,而不是用户)扩展名的合法用途。基本上充当来自可靠来源的代码的东西。
答案 13 :(得分:0)
不直接使用,但preg_replace的/ e修饰符使用eval,非常方便。请参阅http://php.net/preg_replace上的示例#4。
它是邪恶的还是坏的是主观的,完全取决于你在特定背景下认为“好”的东西。处理不受信任的输入时,通常认为它很糟糕。但是,在其他情况下,它可能很有用。想象一下,在极端的最后期限压力下编写一次性数据转换脚本。在这种情况下,如果eval工作并使事情变得更容易,我就会把它称之为邪恶。
答案 14 :(得分:-1)
这个eval辩论实际上是php背景下的一个很大的误解。关于eval是邪恶的,人们被脑子关注,但通常他们使用include
没有问题,虽然include基本上是相同的。包含foo与eval file_get_contents foo相同,所以每当你包含一些东西时,你就会犯下致命的罪恶。