PHP—从模型加载数据库对象的最佳方法,但是否只有一个实例?

PHP—从模型加载数据库对象的最佳方法,但是否只有一个实例?,php,database,model-view-controller,Php,Database,Model View Controller,这是我的问题,我构建了一个很小的PHP MVC框架。 现在,当我在控制器,我应该能够加载一个模型。 我有一些名为Users.php、Pages.php等数据库表的模型 所有的控制器都扩展了BaseController,所有的模型都扩展了BaseModel,这样我就可以为所有的控制器提供一些方法。与任何控制器一样,我可以使用如下loadModel方法: $usersModel = $this->loadModel("Users"); $database = $this->loadDa

这是我的问题,我构建了一个很小的PHP MVC框架。 现在,当我在控制器,我应该能够加载一个模型。 我有一些名为Users.php、Pages.php等数据库表的模型

所有的控制器都扩展了BaseController,所有的模型都扩展了BaseModel,这样我就可以为所有的控制器提供一些方法。与任何控制器一样,我可以使用如下loadModel方法:

$usersModel = $this->loadModel("Users");
$database = $this->loadDatabase();
$data = $database->fetchAssoc("SELECT * FROM users WHERE name = ?", array("someone"));
public function getDatabase()
{

    $reg = \Core\Registry\Registry::getInstance();
    $db = $reg->getObject("database");
    if(!isset($db))
    {
        require_once("Application/Config/Database.php");

        $dns      = "{$db_config['db_driver']}:host={$db_config['db_host']};dbname={$db_config['db_name']}";
        $username = $db_config['db_user'];
        $password = $db_config['db_pass'];
        $options  = $db_config['db_options'];                

        $db = new \Core\Database\Database($dns, $username, $password, $options); 

        $reg->setObject('database', $db);
    }
    return $reg->getObject('database');

}
现在$usersModel将成为表示users数据库表的对象,从那个里我将打开数据库连接,并从users表中获取、更新和删除内容

为了从我的模型中获得数据库连接,baseModel有方法loadDatabase(),我使用它如下:

$usersModel = $this->loadModel("Users");
$database = $this->loadDatabase();
$data = $database->fetchAssoc("SELECT * FROM users WHERE name = ?", array("someone"));
public function getDatabase()
{

    $reg = \Core\Registry\Registry::getInstance();
    $db = $reg->getObject("database");
    if(!isset($db))
    {
        require_once("Application/Config/Database.php");

        $dns      = "{$db_config['db_driver']}:host={$db_config['db_host']};dbname={$db_config['db_name']}";
        $username = $db_config['db_user'];
        $password = $db_config['db_pass'];
        $options  = $db_config['db_options'];                

        $db = new \Core\Database\Database($dns, $username, $password, $options); 

        $reg->setObject('database', $db);
    }
    return $reg->getObject('database');

}
这将返回一个类,该类是围绕PDO的薄层,因此我可以使用如下内容:

$usersModel = $this->loadModel("Users");
$database = $this->loadDatabase();
$data = $database->fetchAssoc("SELECT * FROM users WHERE name = ?", array("someone"));
public function getDatabase()
{

    $reg = \Core\Registry\Registry::getInstance();
    $db = $reg->getObject("database");
    if(!isset($db))
    {
        require_once("Application/Config/Database.php");

        $dns      = "{$db_config['db_driver']}:host={$db_config['db_host']};dbname={$db_config['db_name']}";
        $username = $db_config['db_user'];
        $password = $db_config['db_pass'];
        $options  = $db_config['db_options'];                

        $db = new \Core\Database\Database($dns, $username, $password, $options); 

        $reg->setObject('database', $db);
    }
    return $reg->getObject('database');

}
这就是我如何将一些$data从模型返回到控制器的方法

所以基本上,控制器可以加载一个模型,然后调用该模型上的方法,这些方法将返回一些数据或更新或删除等

现在,控制器可以加载多个模型。每个模型都应该加载数据库,这就是它变得复杂的地方。我只需要一个到数据库的连接

以下是loadDatabase方法的外观:

    public function loadDatabase()
    {
        // Get database configuration  
        require_once("Application/Config/Database.php");

        // Build configuration the way Database Object expects it
        $dns      = "{$db_config['db_driver']}:host={$db_config['db_host']};dbname={$db_config['db_name']}";
        $username = $db_config['db_user'];
        $password = $db_config['db_pass'];
        $options  = $db_config['db_options'];

        // Return new Database object
        return new \Core\Database\Database($dns, $username, $password, $options);

    }
所以,在加载数据库对象之前,必须加载数据库连接的配置,正如数据库对象构造函数所期望的那样。然后实例化新的数据库对象并返回它

现在我卡住了,我不知道这是从模型加载数据库的正确方法吗? 我应该如何设置,我应该如何从模型内部加载数据库,以便始终只有一个数据库对象实例。因为如果我在控制器中执行类似操作:

$users = $this->loadModel("Users");
$pages = $this->loadModel("Pages");

$users->doSomethingThatNeedsDatabase();
$users->doSomethingThatNeedsDatabase();
$pages->doSomethingThatNeedsDatabase();
我将创建3个数据库对象:(

所以我的问题是,我应该如何从模型内部加载数据库,以及该方法应该如何在BaseModel中查看? 如果我想使用2个数据库,那么这个设置会有一些大问题。 如果不使用单例模式,如何实现这一点

现在,我也有这样的想法:

$usersModel = $this->loadModel("Users");
$database = $this->loadDatabase();
$data = $database->fetchAssoc("SELECT * FROM users WHERE name = ?", array("someone"));
public function getDatabase()
{

    $reg = \Core\Registry\Registry::getInstance();
    $db = $reg->getObject("database");
    if(!isset($db))
    {
        require_once("Application/Config/Database.php");

        $dns      = "{$db_config['db_driver']}:host={$db_config['db_host']};dbname={$db_config['db_name']}";
        $username = $db_config['db_user'];
        $password = $db_config['db_pass'];
        $options  = $db_config['db_options'];                

        $db = new \Core\Database\Database($dns, $username, $password, $options); 

        $reg->setObject('database', $db);
    }
    return $reg->getObject('database');

}
这是注册表模式,我可以在其中保存共享对象。所以当模型要求DB连接时,我可以检查DB类是否在注册表中,并返回它,如果不在注册表中,我将安装并返回…最令人困惑的是,我需要加载配置数组

那么,从模型加载数据库的最佳方式是什么呢

谢谢阅读,这是一个很长的问题,但这让我很困扰,我希望有人能帮我解决这个问题…谢谢!

试试这个:

class Registry
{
    /** @return Registry */
    public static function getInstance() {}

    public function getObject($key) {}
    public function setObject($key, $value) {}

    /** @return bool */
    public function isObjectExists($key) {}
}

class Db
{
    const DB_ONE = 'db_one';
    const DB_TWO = 'db_two';

    protected static $_config = array(
        self::DB_ONE => array(),
        self::DB_TWO => array(),
    );

    public static function getConnection($dbName) {}
}


abstract class BaseModel
{
    abstract protected function _getDbName();

    protected function _getConnection()
    {
        $dbName = $this->_getDbName();

        if (!Registry::getInstance()->isObjectExists($dbName)) {
            Registry::getInstance()->setObject($dbName, Db::getConnection($dbName));
        }

        return Registry::getInstance()->getObject($dbName);
    }
}

class UserModel extends BaseModel
{
    protected function _getDbName()
    {
        return Db::DB_ONE;
    }
}

class PostModel extends BaseModel
{
    protected function _getDbName()
    {
        return Db::DB_TWO;
    }
}

祝你好运!

这些模型使用依赖注入模式的最佳方式

public function loadModel() {
    $db = $this->loadDatabase();
    $model = new Model();
    $model->setDatabase($db);
    return $model;
}

其中
loadDatabase()
应该在初始化一次后返回数据库连接的简单实例。

解决这个问题的方法是错误的

与每次手动创建一个新的“模型”然后进行配置不同,您应该创建一个为您实现该功能的结构(极其简化的版本):

您将在index.php或bootstrap.php中使用的此类,或您用作应用程序入口点的任何其他文件:

// at the bootstrap level
$modelFactory = new ModelFactory( new PDO(...) );

// i am assuming that you could get $controllerName 
// and $action from routing mechanism
$controller = new {$controllerName}( $modelFactory );
$controller->{$action}();
您遇到的主要问题实际上是由于误解了模型是什么造成的。在适当的MVC中,模型是一个层,而不是一个特定的类。模型层由多个类/实例组成,主要有两个职责:

  • 域业务逻辑
  • 数据存取和存储
第一组中的实例通常被调用或(有点类似于的情况)。它们处理验证、计算和不同的条件,但不知道信息是如何存储的以及存储在哪里的。它不会改变您开具发票的方式,无论数据来自SQL、远程REST API还是MS Word文档的屏幕截图

另一组主要由。它们存储和检索域对象中的信息。这通常是SQL所在的位置。但映射器并不总是直接映射到DB架构。在经典的多对多结构中,可能有1个或2个或3个映射器为存储服务。映射器通常每个域对象一个。但即使这样,我这不是强制性的

在控制器中,它看起来都是这样的

public function actionFooBar()
{
    $mapper = $this->modelFactory->buildMapper( 'Book' );
    $book = $this->modelFactory->buildObject( 'Book' );
    $patron = $this->modelFactory->buildObject( 'Patron' );

    $book->setTitle('Neuromancer');
    $mapper->fetch( $book );

    $patron->setId( $_GET['uid']);

    if ( $book->isAvailable() )
    {
        $book->lendTo( $user );
    }

    $mapper->store( $book );

}
也许这会给你一些指示,告诉你应该朝哪个方向走

一些附加视频材料:

  • ()

您可以在代码开始时配置和初始化数据库对象,然后将其插入注册表,并在您从注册表中提取它的模型中。
$db=new db($config);registry::set(“\uuuuuuu db\uuuuuuuuuuu',$db);
行“$instance=new{$name}($this->connection);”在您的modelfactory类中,我遇到了一个致命错误。我必须从$name变量中删除{}才能解决此问题。不确定原因,因为它看起来是正确的。@billmalarky,嗯..这些代码都没有经过实际测试。很可能有类似的错误。有一些更新的帖子,与此主题和主题相关。