<?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 {}
<?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{}
}
答案 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
之后放入一堆语法不正确的代码。即使代码执行不能在那里解析,解析器仍然会给你一个错误。