PHP - require_once 和类继承问题

Posted

技术标签:

【中文标题】PHP - require_once 和类继承问题【英文标题】:PHP - require_once and class inheritance issue 【发布时间】:2013-09-10 23:48:58 【问题描述】:

我收到一个致命错误:Fatal error: Class 'Foo1' not found in .../Foo2.php on line 5 包含以下文件:

index.php:

<?php
require_once("./Foo1.php");
?>
<h1>Success</h1>

Foo1.php:

<?php
require_once('./IFoo.php');
require_once('./Bar.php');

class Foo1 implements IFoo

    /** @var  Bar */
    private $bar;

IFoo.php:

<?php
interface IFoo 

Bar.php:

<?php
require_once('./Foo2.php');

class Bar 
    /** @var  Foo2 */
    private $foo;

Foo2.php:

<?php
require_once("./Foo1.php");

class Foo2 extends Foo1


问题:

    如何解决这种情况? 为什么当我禁止 implements IFoo 语句时,这段代码可以工作?

更新 大多数提出的解决方案都涉及自动加载。不幸的是,我的问题出在一个有很多现有代码和很多不良做法的旧项目上。我们离 PSR-0 标准还差得很远。

在性能方面引入自动加载的成本是多少?

【问题讨论】:

【参考方案1】:
    使用autoloading 功能。不要在具有类定义的文件中添加任何其他可执行代码(如 require / include)。 因为Foo1实现IFoo时,php对IFoo一无所知,所以无法注册类Foo1。由于没有注册自动加载器,php 开始解释代码,省略 Foo1.php 中的类声明,直到包含和解析其他文件。当它到达Foo2.php 时,它不包括Foo1.php(由于require_once)并开始解释文件-在这里它遇到类Foo1,由于当时不存在接口实现,因此跳过了定义。此时 php 不知道 Foo1 是在已经需要的Foo1.php 中声明的,因为它没有机会完全解释这个文件。

【讨论】:

1. autoloading 可能是一个解决方案,但我有点犹豫是否要介绍它的使用,因为我不知道对性能的影响。 2.“因为当Foo1实现IFoo时,php对IFoo一无所知”——我不明白,因为在Foo1.php中首先包含的是IFoo... 包含但不解析,因为它实现了未知接口,所以不是注册已知类,而是逐行执行文件,深入require_once。至于性能,there is no reason not to autoload【参考方案2】:

如果你把Foo1.php文件修改成这个

<?php
require_once('./IFoo.php');

class Foo1 implements IFoo

/** @var  Bar */
private $bar;


require_once('./Bar.php');

?>

这行得通。

原因是 PHP 是解释型语言(解释器逐行执行脚本)。 因此,在您的情况下,解释器错过了 Foo1 声明语句,并在遇到 Foo2.php 中未定义的类 Foo1 时引发错误。

【讨论】:

有趣的命题...这是否意味着管理包含的最佳方法首先是类将实现的父级或接口。并在类之后,包括运行时使用的其他类?【参考方案3】:

我建议使用Autoloading Standard PSR-0。它描述了自动加载器互操作性必须遵守的强制性要求。

无论如何,在这种情况下:

Foo1.php

您包括Bar.php,并且因为这条线:require_once('./Foo2.php');Class Foo2 扩展Class Foo1。但是Foo1 类还没有定义!只有在它的定义之后,你才能扩展一个类。

所以看来require_once('./Foo2.php'); 不应该在Bar.php 中。或者你应该在class Foo1 定义之后移动require_once('./Bar.php');

<?php
require_once('./IFoo.php');

class Foo1 implements IFoo

    /** @var  Bar */
    private $bar;


require_once('./Bar.php');

【讨论】:

感谢这两个提议。请参阅我的问题更新。因此,如果我不想使用自动加载,解决方案是首先导入类声明所需的类。并在实现之后,包括运行时需要的其他类...? @AlbanSoupper 如果您不想使用自动加载,您真正关心的是:在定义之前不要扩展或不要创建新的类实例。因为php逐行解释脚本。 @AlbanSoupper 在单独的文件中定义每个ClassInterfacerequire_once 只需要当前类的接口或类。对你有很大帮助。

以上是关于PHP - require_once 和类继承问题的主要内容,如果未能解决你的问题,请参考以下文章

使用 require_once() 或不使用 require_once()

PHP5,require_once,打开流失败

PHP多继承实现--Traits

php中的require_once

PHP - 类构造中的Require_once

错误 500 Require_once