从PHP中的自动加载类加载扩展类

时间:2014-04-20 01:57:12

标签: php autoload

我试图找到类似的问题或场景,但我无法做到。我有以下结构:

  • 类/
    • 开发/
      • class1.php
      • class2.php
    • class1.php
    • class2.php
    • class3.php

然后,代码调用:

$class1 = new class1();
$class2 = new class2();
$class3 = new class3();

' dev' folder包含应覆盖根类的类。 ' dev'内有一个扩展的class1。文件夹,class2,但不是class3。目前,我试图在自动加载功能中加载此扩展类,这有效,但不是我期望的方式:D

不是从根文件夹加载class1,而是从' dev'中加载class1。文件夹,它只在离开自动加载功能后才加载根类。简化代码,我有类似的东西:

function $autoloader($class) {
    if (!file_exists($class)) {
        echo 'failed - fallback or do something else';
        return false;
    }
    require_once($class);

    // Instantiates extended class from 'dev'
    if (file_exists($classFromDevFolder)) {
        require_once($classFromDevFolder);
        $newClass = new $classFromDevFolder();
        unset($newClass);
    }            
}

它有效,从“开发”中加载课程。文件夹,并精细扩展class1。但是,如上所述,它在根类之前实例化dev类。我假设是因为它在自动加载函数中加载了dev类,即使在调用根类之后也是如此。

你们对如何实现它有任何想法吗?我还想创建另一个函数来加载' dev'类,但我不知道在哪里放置它以使这个函数适用于任何类。


我添加了这个非常简化的代码示例,以便更好地说明和澄清我希望实现的目标。

根文件夹:

class Class1() {
    ...
    public function __construct() {
        $this->x = 1;
    }
    ...
}

开发文件夹:

class Class1_Dev extends Class1() {
    ...
    public function __construct() {
        $this->x = 2;
    }
    ...
}

自动加载机:

function autoloader($class) {
    if (!file_exists($class)) {
        echo 'failed - fallback or something else';
        return false;
    }
    require_once($class);
    ...
    $devClass = 'dev/' . $class;
    if (file_exists($devClass)) {
        require_once($devClass);
        $newClassName = $class . '_Dev';

        // Here is the issue: it instantiates Class1_Dev before Class1,
        // and ultimately, Class1 keeps 'x' as 1, not 2
        $newClass = new $newClassName();
    }
}

代码:

$class1 = new Class1();
var_dump($class1->x);

预计$ class-> x为2,而不是1.

1 个答案:

答案 0 :(得分:0)

如果我正确理解您的问题,您希望首先从dev文件夹加载类,或者从根文件夹中不存在它们。您可以通过spl_autolaod_register轻松实现此目的:

// Please be aware that anonymous function are first available for spl_autoload_register as of PHP 5.3.0
spl_autoload_register(function ($class) {

    include 'classes/dev/' . $class . '.php';

    if (! class_exists($class)) {
        include 'classes/' . $class . '.php';
    }

}); 

然后你应该可以打电话给你的班级

$class1 = new class1();
$class2 = new class2();
$class3 = new class3();

理想情况下,从dev文件夹加载class1和class 2,从根文件夹加载class3。


<强>更新

正如已经在评论中发布的那样,如果你加载两个具有相同名称的类,第一个加载的类将是持久的类,如果你想要加载另一个具有相同类名的类,这将失败。

我不太确定你为什么要这样做?

但是看看你的代码,在使用我之前发布的自动加载方法时,我可以想到一些实现上述目的的方法。

使用实现共享逻辑的基类然后通过不同文件夹中的类扩展它的一个示例:

根文件夹

class BaseClass1 {
   protected $devMode;
   protected $x;

   public function __construct() {
        $this->devMode = false;
        $this->x = 0;
   }

   public function isDevClass() {
        return $this->devMode;
   }

   public function getX() {
        return $this->x;
    }
}

开发文件夹:

class Class1 extends BaseClass1 {

    public function __construct() {
        $this->devMode = true;
        $this->x = 2;
    }
    ...
}

根文件夹:

class Class1 extends BaseClass1 {

    public function __construct() {
        parent::__construct();
        $this->x = 1;
    }
    ...
}

现在依赖于这种情况,如果我们在dev文件夹中有一个class1类,其构造函数会覆盖基类,我们可以识别该类的加载位置:

$class1 = new class1();

// Check if devMode is set (false by default)
if ($class1->isDevClass()) {
    // Class1 was loaded from dev, do bla; 
} else {
   // Class1 was loaded from root, do bla; 
}

// or
echo $class1->getX(); // will return 1 or 2 depending on the folder the class was loaded from

不确定这是否是您正在寻找的。还有其他方法可以做到这一点。您应该尽可能减少冗余。最后,您宁愿定义一个站点范围的常量,然后您可以将其作为标识符传递到类的构造函数中。然后,您可以根据构造类时设置的内容在类中产生细微差别。

例如完全删除冗余dev文件夹:

define("DEV", true);
...

class Class1 {
    protected $devMode;
    protected $x;

    public function __construct($mode = false) {
        $this->devMode = $mode;

        if ($this->devMode) {
            $this->x = 2;
        } else {
            $this->x = 1;
        }
    }

    public function doSomething() {
        if ($this->devMode) {
            // Do only devMode specific stuff
        }
    }
    ...
}
...
$class1 = new class1(DEV);

希望这有帮助。