我有一个带有手动类加载和以下层次结构树的遗留项目:
A --> B --> C --> C1
\---> C2
要获得C
作为切入点,我写了以下内容:
<?php // index.php
require_once __DIR__ . '/C.php';
<?php // A.php
class A {
}
<?php // B.php
require_once __DIR__ . '/A.php';
class B extends A {
}
<?php // C.php
require_once __DIR__ . '/B.php';
require_once __DIR__ . '/C1.php';
require_once __DIR__ . '/C2.php';
class C extends B {
}
<?php // C1.php
class C1 extends C {
}
<?php // C2.php
class C2 extends C {
}
但index.php
抛出:
致命错误:第2行的C:\ test \ C1.php中找不到“C”类
那是class C1 extends C
。
我必须对PHP内部有一些基本的误解,因为如果我用相应的文件内容替换每个require_once
,它会运行得很完美。我错过了什么?
答案 0 :(得分:4)
类C
不应该知道它的衍生物,所以它应该是
<?php // C.php
require_once __DIR__ . '/B.php';
class C extends B {
}
<?php // C1.php
require_once __DIR__ . '/C.php';
class C1 extends C {
}
<?php // C2.php
require_once __DIR__ . '/C.php';
class C2 extends C {
}
答案 1 :(得分:1)
目前您定义了C1
和C2
类,但尚未定义类C
,因此PHP会导致致命错误。
以下是一个示例,了解应该更改哪些内容才能使其正常工作:
<?php // C.php
require_once __DIR__ . '/B.php';
class C extends B {
}
require_once __DIR__ . '/C1.php';
require_once __DIR__ . '/C2.php';
将所有类编写在单个文件中是有效的,因为PHP编译器正在处理整个文件内容并相应地使用所需的类。调用在文件末尾定义的函数时会出现相同的行为。
使用includes,编译器仅使用先前编译的资源。
答案 2 :(得分:1)
问题始于此文件:
<?php // C.php
require_once __DIR__ . '/B.php';
require_once __DIR__ . '/C1.php';
require_once __DIR__ . '/C2.php';
class C extends B {
}
include()/include_once()/require()/require_once()
语句不将包含文件的内容复制粘贴到它们出现的文件中。
实际的包含发生在运行时。当编译器看到该行时:
class C extends B
它会触发错误,因为它对B
一无所知。
如果您放置B.php
文件的内容而不是require_once
语句,则情况会有所不同。在编译C.php
期间,编译器会了解B
的定义,并能够基于它创建class C
的定义。
使其运行的最佳方式(截至2017年)是使用autoloading(大约10年前不推荐手动加载)。您可以编写一个符合项目需求的简单自动加载器功能(如文档中所述),或者更好的是,您可以将所有课程放在namespace中,遵循PSR-4建议和使用Composer生成自动加载器。
<强>更新强>
使用自动加载器无需使用include()
/ require()
。项目文件的内容如下所示:
<?php // A.php
namespace MyProject;
class A {
}
<?php // B.php
namespace MyProject;
class B extends A {
}
<?php // C.php
namespace MyProject;
class C extends B {
}
// ...and so on...
<强>结论:强>
正如OP在问题中指定的那样,它是一个使用include()
/ require()
语句手动加载的遗留项目。这个答案提出了一种替代方法,这种方法最适合新项目。对于遗留项目,大多数情况下实现自动加载(以及删除分散在整个项目中的include()
/ require()
语句)所需的工作量超出了优势。
答案 3 :(得分:1)
我将以最简单的方式解释错误发生的原因。
当您使用require_once
语句时,编译器会在看到语句时包含所需的文件,因此我们可以恢复所有包含的文件,如下所示:
//Start index.php
// index.php require File C
// file C.php requires B.php
// file B.php requires A.php
class A {
}
// end file A.php
class B extends A {
}
//end file B.php
//file C.php require C1.php
//file C1.php
class C1 extends C {
}
//// ** ERROR class C still not declared ! PHP Stops.
所以你需要在扩展它之前包含C类:)
答案 4 :(得分:1)
这是问题所在。
PHP将在加载后解释整个脚本。这包括类函数和其他符号的声明。条件函数/类有一个值得注意的例外。
例如,这适用于https://eval.in/727681:
class A {
}
// end file A.php
class B extends A {
}
//end file B.php
//file C.php require C1.php
//file C1.php
class C1 extends C {
}
class C extends B {
}
但是这个不是(https://eval.in/727682):
class A {
}
// end file A.php
class B extends A {
}
//end file B.php
//file C.php require C1.php
//file C1.php
class C1 extends C {
}
if (true) {
class C extends B {
}
}
致命错误:未找到“C”类
现在真正的问题是,PHP通常会“向前看”以查看即将发布的内容,明确声明,但会独立处理每个文件。这意味着 你不能包含一个带有“promise”的类文件,你最终会声明它的依赖项。