【发布时间】:2011-10-29 20:07:45
【问题描述】:
背景: 我正在为 PHP 应用程序构建一个自动化测试框架,我需要一种方法来有效地封装与外部系统的通信的"stub out" 类。例如,当测试使用 DB 包装器类 Y 的类 X 时,我希望能够在对类 X 运行自动化测试时“换入”类 Y 的“假”版本(这样我就不必这样做了)作为测试的一部分,完整设置 + 拆除真实数据库的状态)。
问题: PHP 允许“条件包含”,这意味着 include/require 指令基本上是作为处理文件“主要”逻辑的一部分来处理的,例如:
if (condition) {
require_once('path/to/file');
}
问题是我无法弄清楚当包含文件的“主”逻辑调用“return”时会发生什么。包含文件中的所有对象(定义、类、函数等)是否都导入到调用 include/require 的文件中?或者处理会随着退货而停止?
示例: 考虑这三个文件:
A.inc
define('MOCK_Z', true);
require_once('Z.inc');
class Z {
public function foo() {
print "This is foo() from a local version of class Z.\n";
}
}
$a = new Z();
$a->foo();
B.inc
define('MOCK_Z', true);
require_once('Z.inc');
$a = new Z();
$a->foo();
Z.inc
if (defined ('MOCK_Z')) {
return true;
}
class Z {
function foo() {
print "This is foo() from the original version of class Z.\n";
}
}
我观察到以下行为:
$ php A.inc
> This is foo() from a local version of class Z.
$ php B.inc
> This is foo() from the original version of class Z.
这很奇怪: 如果 require_once() 包含所有定义的代码对象,那么“php A.inc”应该用类似
的消息来抱怨Fatal error: Cannot redeclare class Z
如果 require_once() 只包含定义的代码对象直到“返回”,那么“php B.inc”应该抱怨如下消息:
Fatal error: Class 'Z' not found
问题: 谁能在这里解释准确 PHP 正在做什么?这对我来说实际上很重要,因为我需要一个强大的习惯用法来处理“模拟”类的包含。
【问题讨论】:
-
首先,我不确定您要完成什么。单元测试不应该需要任何 hacky 定义或条件包含。但除此之外,这是有趣的双重行为。没有返回,你会得到一个重复的类错误。不确定手册是否解决了这个问题。
-
@Matthew - 我无法在 PHP 手册中找到任何解释我在我的 OP 中描述的行为的内容(因此是问题)。至于单元测试和黑客攻击,我发现在实践中,如果不以某种方式注入模拟对象(又名测试替身),要获得比非常适度的测试覆盖率还远非易事,而且由于 PHP 不会非常“打猴子补丁”简单(比如 Python),然后我不得不在 hacking 包含、物理替换文件和颠覆类层次结构之间做出选择以实现这一目标。