当代码甚至没有达到执行点时,我的类如何被包含两次?

时间:2012-03-07 17:52:46

标签: php include

a.php只会

<?php

echo "AAA\n";
if(class_exists('NotImplementedException')) {
    echo "BBB\n";
    return;
    echo "DDD\n";
}

echo "CCC\n";

/**
 * Thrown when a feature is not yet implemented.
 */
class NotImplementedException extends Exception {}

b.php

<?php
include 'a.php';
include 'a.php';

当我运行b.php时,我得到:

AAA
BBB
PHP Fatal error:  Cannot redeclare class NotImplementedException in /home/mark/Tests/IncludeTwice/a.php on line 15

这里发生了什么?我期望的输出是

AAA
CCC
(class gets declared for first time)
AAA
BBB
(execution stops)

对于那些说“解释器首先扫描并解析整个文件”的人:那为什么会这样做?:

<?php

class A{}

if(!class_exists('A')) {
    class A{}
}

2 个答案:

答案 0 :(得分:3)

我认为一部分是一个错误......

如果要扩展类,PHP解释器的工作方式会有所不同。

这有效:

<?php

class a {}
exit();
class a extends Exception {}

?>

这不是:

<?php

class a extends Exception {}
exit();
class a {}

?>

从我在PHP 5.4.0 source中可以看到,有两个不同的函数来处理类的绑定:do_bind_class:4494用于独立类,do_bind_inherited_class:4533用于继承类(使用扩展关键字)。

独立函数有一个条件,它在编译时忽略重复的类定义,以防它在运行时永远不会被命中。继承的类版本缺少此条件(可能是故意的,也许不是)。

我会修补继承的函数,使其具有相同的条件,测试并提交给开发人员。

另一部分是一个特征......

至于你的条件类部分:我相信PHP会在编译时加载你的类,如果它在全局范围内声明,但是如果它包含在一个块中,它将不会被加载,直到它被执行。 / p>

这有效:

<?php

$a = new A();

//{
    class A {}
//}

?>

这不起作用,即使它在逻辑上是相同的:

<?php

$a = new A();

{
    class A {}
}

?>

当您将这两个功能组合在一起时,您的问题就出现了,因为您的类既是继承类又是在全局范围内声明的。

答案 1 :(得分:2)

您需要将类声明移到else调用的class_exists()语句中。你两次都声明你包括a.php。 return不会阻止解析文件,在这种情况下包括类声明。因此,虽然脚本执行没有超过您的返回,但PHP发现您已经多次声明NotImplementedException

可以把它想象成在return之后放入一堆语法不正确的代码。即使代码执行不能在那里解析,解析器仍然会给你一个错误。