构建一个面向对象的DBAL类,它实现了延迟加载的连接

时间:2012-03-16 18:57:09

标签: php database oop

我正在努力使我的应用程序尽可能面向OOP,我想知道一种安全,干净的方式来实现我的数据库。基本上我所拥有的是具有多种方法的数据库类型,例如connect(),add(),update(),remove(),以操纵数据库。每当我需要连接到另一个类的数据库时,有没有一种好的方法可以自动实现它?或者,如果有一本好书来处理创建这种类型的设计。对不起,如果不清楚的话。

3 个答案:

答案 0 :(得分:1)

我建议您从MVC借用一些概念。在这种情况下,关于模型层的想法。正确编写的模型层由两种主要类型的实例组成:

  • 域对象:负责所有域业务逻辑(阅读更多herehere
  • 数据访问对象:处理所有存储。通常实现为DataMappers。

想法是域对象完全没有意识到存在任何类型的存储。他们不在乎。如果信息来自SQL数据库,远程REST API或MSWord文档的屏幕截图,则发票的业务逻辑不会更改。

另一方面,数据访问对象没有指示业务逻辑如何工作。只接收一个对象,并将数据提取到其中,或将数据存储到某个持久性介质中。如果您想更多地了解DataMappers,那么您应该read herewatch this演示文稿(幻灯片here)。

现在关于懒惰的连接。这就是我实现它的方式:

// somewhere in bootstrap.php

/* --snip-- */
$connection = function(){ 
    $instance = new PDO( .... );
    $instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    return $instance;
};

$mapperFactory = new MapperFactory( $connection );
/* --snip-- */

MapperFactory的实现如下:

// different file where the class is defined
class MapperFactory
{
    protected $connection_provider = null;
    protected $connection = null;

    public function __construct( $connection_provider )
    {
        $this->connection_provider = $connection_provider;
    }

    public function build( $classNname )
    {
        $instance = new $className;
        if ( $instance instanceof  SqlDataMapper )
        {
            if ( !$this->connection )
            {
                $this->establishConnection(); 
            }
            $instance->setConnection( $this->connection );
        }

        return $instance;
    }

    protected function establishConnection()
    {
        $this->connection = call_user_func( $this->connection_provider );
    }
}

您需要的只是将$mapperFactory bootstrap 传递给将要使用它的类。

如果您认真学习OO解决问题的方法,那么这将是必读的阅读材料清单(代码示例将使用Java,但这些想法在这里很重要):

答案 1 :(得分:0)

最好的方法就是使用包含在某种数据库管理器中的PDO或Mysqli,它可以读取您在boostrapping中设置的配置信息。然后你要么让这个类成为单例,要么使用某种自动依赖注入来确保你可以从模型和控制器层中的每一个中获取它(假设是mvc / hmvc)。

我从一个单身人士开始,因为其非常简短的例子来证明:

class DatabaseManager
{
   protected $_connections = array();

   protected static $_configPath = 'config';

   protected static $_configFile = 'databases.json'

   protected static $_instance;

   protected $_defaultConnection;


   protected __construct()
   {
      $this->_loadConfig();
   }

   protected loadConfig()
   {
      if(!($file = realpath(self::$_configPath . DIRECTORY_SEPARATOR . self::$_configFile)) {
          throw new Exception('Configuration file does not exist.');
      }

      if(!($config = file_get_contents($file)) {
         throw new Exception('Could not read configuration.');
      }

      if(!($configData = json_decode($config, true)) {
         throw new Exception('Could not parse JSON.');
      }

      $this->_connections = $configData;
   }

   public static function setConfigDir($path)
   {
       self::$_configDir = $path;
   }

   public static function setConfigFile($filename) {
      self::$_configFile = $filename;
   }

   public static function getInstance() {
      if(!self::$_instance) {
         self::$_instance = new self();
      }

      return self::$_instance;
   }

   public static function getConnection($key = null) {
       $instance = self::getInstance();
       $key = null === $key ? $instance->_defaultConnection : $key;

       if(!$instance->_connections[$key] instanceof PDO) {
          if(is_array($instance->_connections[$key]) {
             $instance->_connections[$key] = new PDO($instance->_connections[$key]['dsn'], $instance->_connections[$key]['username'], $instance->_connections[$key]['password']);

          } else {
             throw new Exception ("Invalid connection \"$key\"");
          }
       }

       return $instance->_connections[$key];       
   }
}

现在您可能希望验证配置文件(确保它至少包含一个连接,并确保每个连接定义都包含dsn,用户名和密码)。并且你可能想要更好的错误hadling,但据说使用这个就像:

在你的引导程序中:

DatabaseManager::setConfigPath('/path/to/config');
DatabaseManager::setConfigFile('databases.json');

然后几乎在你的应用中的任何地方:

// get a connection - they are lazy loaded - YAY!
$pdoObject = DatabaseManager::getInstance()->getConnection('my_connection_name');

// use PDO as normal
$stmt = $pdoObject->prepare('SELECT * from test');
$stmt->execute();
// do stuff with statement and returned results

现在说了这么多,如果你想要PDO以上的经理我会推荐Doctrine2 DBAL或者你想要/需要一个完整的ORM Doctrine2 ORM

答案 2 :(得分:-1)

甚至更好,使用PHP ActiveRecord:

ActiveRecord Site

对象关系映射模式。