组织PHP OOP类以使用DB

组织PHP OOP类以使用DB,php,database,oop,Php,Database,Oop,今天我有一个PHP项目,它的类结构非常奇怪。像这样: db_base `-- db_base_ext extends db_base +-- module_1 extends db_base_ext +-- module_2 extends db_base_ext . ... +-- module_N extends db_base_ext `-- db_user extends db_base_ext c

今天我有一个PHP项目,它的类结构非常奇怪。像这样:

db_base
  `-- db_base_ext extends db_base
        +-- module_1 extends db_base_ext
        +-- module_2 extends db_base_ext
        .   ...
        +-- module_N extends db_base_ext
        `-- db_user extends db_base_ext

class_1
  `-- submodule_1_1 extends class_1
db_base连接到db in__构造,并有一些辅助方法

执行的示例:

$db = new db_user();
$user = new user($db);
unset($db);

$db = new module_2();
我不喜欢在这段代码中我们两次连接到DB,整个类结构不是很好

我怎样才能做得更好?我的意思是只创建一个DB实例,然后使用与DB对应的任何类


单例模式对此有好处吗?

您应该考虑在DB类中使用单例模式


它使用PDO进行通信,但对于mysqli或其他类型也应该有效。

您应该考虑对DB类使用单例模式

。 它使用PDO进行通信,但也应该对mysqli或其他类型有效。

使用正确的类名 首先,我注意到项目中的类被命名为like函数。如果项目尝试使用PEAR命名约定,它应该正确地使用

使模块独立于数据库类 您应该断开模块与db_base_ext类的连接。如果模块需要访问数据库实例,则可以使用构造函数参数或setter提供该模块。它不应该直接扩展类

$module = new Module($database);
使用正确的类名 首先,我注意到项目中的类被命名为like函数。如果项目尝试使用PEAR命名约定,它应该正确地使用

使模块独立于数据库类 您应该断开模块与db_base_ext类的连接。如果模块需要访问数据库实例,则可以使用构造函数参数或setter提供该模块。它不应该直接扩展类

$module = new Module($database);

你的问题是,你的结构

module_2 extends db_base_ext
db_user extends db_base_ext
submodule_1_1 extends class_1
他们都打破了和

我怎样才能做得更好。我的意思是只创建一个DB实例,然后 这项工作与任何类对应的数据库,是可能的

这是一条路要走。您将实例化一个db实例,并且您的所有类将共享同一个$db实例

final class MySQLPDO extends PDO
{
    public function __construct(array $params)
    {
      parent::__construct(sprintf('mysql: host=%s; dbname=%s', $params['host'], $params['database']), $params['username'], $params['password']);

      $this->setAttribute(parent::MYSQL_ATTR_INIT_COMMAND, 'SET NAMES UTF8');
      $this->setAttribute(parent::ATTR_ERRMODE, parent::ERRMODE_EXCEPTION);
      $this->setAttribute(parent::ATTR_EMULATE_PREPARES, false);
      $this->setAttribute(parent::ATTR_DEFAULT_FETCH_MODE, parent::FETCH_ASSOC);

    }
}

$db = new MySQLPDO(array(
     'host'     => 'localhost',
     'database' => 'foo',
     'username' => 'root',
     'password' => '',
));
$user = new User($db);

$module = new Module1($user);
$foo = new Foo($db);
那么,你在这里会得到什么?重用能力和测试能力


注意,您应该避免单例,因为它们引入了另一种形式的全局状态,这不利于单元测试

module_2 extends db_base_ext
db_user extends db_base_ext
submodule_1_1 extends class_1
他们都打破了和

我怎样才能做得更好。我的意思是只创建一个DB实例,然后 这项工作与任何类对应的数据库,是可能的

这是一条路要走。您将实例化一个db实例,并且您的所有类将共享同一个$db实例

final class MySQLPDO extends PDO
{
    public function __construct(array $params)
    {
      parent::__construct(sprintf('mysql: host=%s; dbname=%s', $params['host'], $params['database']), $params['username'], $params['password']);

      $this->setAttribute(parent::MYSQL_ATTR_INIT_COMMAND, 'SET NAMES UTF8');
      $this->setAttribute(parent::ATTR_ERRMODE, parent::ERRMODE_EXCEPTION);
      $this->setAttribute(parent::ATTR_EMULATE_PREPARES, false);
      $this->setAttribute(parent::ATTR_DEFAULT_FETCH_MODE, parent::FETCH_ASSOC);

    }
}

$db = new MySQLPDO(array(
     'host'     => 'localhost',
     'database' => 'foo',
     'username' => 'root',
     'password' => '',
));
$user = new User($db);

$module = new Module1($user);
$foo = new Foo($db);
那么,你在这里会得到什么?重用能力和测试能力


注意,您应该避免单例,因为它们引入了另一种形式的全局状态,这不利于单元测试。

什么让您认为它连接了两次?@jakenoble第一个连接在第一个字符串中,第三个字符串中断开,第二个连接在第五个字符串中。也许可以改用库?可能重复的可能重复的让你认为它连接了两次的内容?@jakenoble第一个连接在第一个字符串中,第三个字符串中断开连接,第二个连接在第五个字符串中。也许可以使用库来代替?可能重复的可能重复的我不知道你的建议的一个实例与单例实现有何不同。我希望你的意思是$module=newmodule1$db@zewa666唯一的区别是,您可以像$db=db::getInstance那样调用您的单例。因为您像DB::getInstance那样调用它,所以引入了另一种形式的全局状态。应该使用DI而不是Singleton…不要命名这个创建类适配器。它所做的只是将params数组的魔术键、未记录的用法、坏主意转换为新的PDO配置。一个函数就可以做到这一点,只需提供配置。但我实际上只是想对名称进行评论:所以适配器作为名称是一种气味,你能想象该类有更好的名称吗?如果你从PDO扩展,它不是PDO提供者,它只是一个PDO,例如MyPDO。当您调用名为provide或类似的方法时,提供程序将返回一个PDO。至少我是这么理解的这个闭包只是一个例子,好吧,PHP5.3已经是生命的终结。如果您给出建议,请将其保存在适当的当前稳定PHP版本中。这不是一个在2008年提出的问题,也不是说关闭是解决问题的方法。我不知道你的建议的一个实例与单例实现有什么不同。我希望你的意思是$module=newmodule1$db@zewa666唯一的区别是,您可以像$db=db::getInstance那样调用您的单例。因为您像DB::getInstance那样调用它,所以引入了另一种形式的全局状态。应该使用DI而不是Singleton…不要命名这个创建类适配器。它所做的只是转换参数
y魔术键,未记录的用法,坏主意进入一个新的PDO配置。一个函数就可以做到这一点,只需提供配置。但我实际上只是想对名称进行评论:所以适配器作为名称是一种气味,你能想象该类有更好的名称吗?如果你从PDO扩展,它不是PDO提供者,它只是一个PDO,例如MyPDO。当您调用名为provide或类似的方法时,提供程序将返回一个PDO。至少我是这么理解的这个闭包只是一个例子,好吧,PHP5.3已经是生命的终结。如果您给出建议,请将其保存在适当的当前稳定PHP版本中。这不是2008年提出的问题,也不是说关闭是解决问题的方法。您确定断开所有模块与db_base_ext的连接是个好主意吗?为什么有必要?例如,在codeigniter中,所有模型都扩展了基本类CI_模型。@Yekver我绝对肯定:只要问问自己这个问题:模块是数据库的一种类型吗?。模块显然不是。因此,它不应该试图表现得像一种数据库或它的扩展。@Yekver确切地调查CI的作用,并做与之相反的事情,您应该可以。您确定断开所有模块与db_base_ext的连接是一个好主意吗?为什么有必要?例如,在codeigniter中,所有模型都扩展了基本类CI_模型。@Yekver我绝对肯定:只要问问自己这个问题:模块是数据库的一种类型吗?。模块显然不是。因此,它不应该试图表现得像一种数据库或它的扩展。@Yekver确切地调查CI的作用,并做与之相反的事情,您应该可以。