3

我有一个类 Database.php,它是一个抽象的 Singleton 类:

<?php

abstract class Database
{
    protected static $_instance;
    ...

    public static function instance()
    {
        $class = get_called_class();

        if (!self::$_instance) {
            self::$_instance = new $class();
        }

        return self::$_instance;
    }
}

?>

其他数据库扩展了这个类并实现了抽象函数,这样我就可以改变我使用的数据库,同时确保我的应用程序只要它使用这个抽象层中的函数仍然可以工作(我已经省略了上面的函数定义代码)。

我在 PDO.php 中有一个 PDO 类。它扩展了数据库,还包括instance()与上述相同的功能,但它没有自己的$_instance变量。

class PDO extends Database
{
    //...

    public static function instance()
    {
        $class = get_called_class();

        if (!self::$_instance) {
                self::$_instance = new $class();
        }

        return self::$_instance;
    }
}

最初我认为我不必instance()在 PDO 类中包含该函数,因为它继承自 Database。但我把它包括在内是因为我收到了这个错误:

Fatal error: Call to undefined method PDO::instance()

问题是即使使用上面的代码,我仍然会收到此错误。我不知道这是否相关,但我遇到了另一个奇怪的错误。我要使用的数据库类型(在本例中为 PDO)存储在一个可通过App::setting('DB'). 我的 MVC 框架中的 Model 基类加载适当的数据库类并将其存储在$this->_db. 这是模型的代码:

<?php

require_once 'Databases/Database.php';

class Model
{
    protected $_db;

    public function __construct()
    {
        $database = App::setting('DB'); // 'PDO' 
        require_once 'Databases/' . $database . '.php';
        $this->_db = $database::instance(); // this is what triggers the error
    }
}

?>

现在这段代码给了我一个错误,我无法重新声明 PDO 类。我在网上搜索,发现问题通常与使用include()而不是require_once(). 我到处检查,我的 Autoloader 没有看到任何include(). 即使require_once()在上面的模型中,它仍然给我错误(这是我唯一需要 PDO 类的地方......)。

为了解决这个错误,我使用了一个创可贴解决方案,我将 Model 构造函数中的 require 替换为:

if (!class_exists($database)) {
    require_once 'Databases/' . $database . '.php';
}

谁能解释这里发生了什么?

4

2 回答 2

7

类名PDO是 PHP 的标准类,因此使用包含类的解决方案PDO实际上永远不会包含您的类。

于 2012-07-30T06:20:18.160 回答
0

我建议使用自动加载。它会让你的生活更简单,你可以摆脱所有这些require电话。

PHP手册中有一个实现,我发现它非常有用。它可能看起来像这样:

function my_autoloader($class) {
    include 'classes/' . $class . '.class.php';
}

spl_autoload_register('my_autoloader');

// Or, using an anonymous function as of PHP 5.3.0
spl_autoload_register(function ($class) {
    include 'classes/' . $class . '.class.php';
});

如果您使用的是 PHP 5.3,还可以考虑使用命名空间。拥有一个良好的结构和默认实现的简单自动加载器实际上更容易:

spl_autoload_extensions(".php"); // comma-separated list
spl_autoload_register();

但是,我记得那里有一个错误。通常我有一个“引导”文件,带有这个自动加载器:

spl_autoload_register(function($class) {
    if(file_exists('./lib/' . str_replace('\\', '/', $class) . '.php')) {
        require_once './lib/' . str_replace('\\', '/', $class) . '.php';
    }
});

使用此机制,您将拥有一个模仿命名空间结构的文件夹结构。使用这种方法,您有一个良好的结构,并且不需要关心包含您的库和其他类。

于 2012-07-30T06:48:43.057 回答