数据库对象类PHP

时间:2012-01-19 17:46:10

标签: php database oop

我最近使用数据库对象超类做了一些项目,我用它来快速进行一次性记录查询/更新,并使用适当的类进行扩展,例如User类。

我发现我写的很多类都有完全相同的方法:query_values(),update(),delete()等。

所以我想出了一个带有如下构造函数的类:

public function __construct($table, $db_object, $record_id = null){
    $this->db = $db_object; // Database object with query methods

    $this->table = $table; // The name of the database table

    $this->get_column_data();

    if(!is_null($record_id)){
        // This retrieves all column values, 
        // stores into private $fields array property
        $this->query_values($record_id);
    }
}

子类构造函数如下所示:

public function __construct($db_object, $record_id = null){
    parent::__construct($this->table, $db_object, $record_id);
}

在$ top属性的顶部定义,因为我们应该知道这个特定对象使用哪个表。

现在,所有常见的记录管理方法都在一个地方,并且特定于该类的方法都是在各自的子类中定义的。

我在这里看到的最大缺点是所有数据字段都被拉出并封装在$ fields属性中,因此需要定义泛型get和set方法(我通常这样做)几乎否定封装*,或者必须为我们想要公开的每个属性专门定义一个方法。

*实施例:     $ user_id = $ User-> id; //不使用我的方法 与     $ user_id = $ User-> _get('id'); //访问$ User-> fields ['id']

你认为这是一个缺点,还是一个加分?目标是易于使用,面向对象(封装),并且只是非常棒!

3 个答案:

答案 0 :(得分:2)

好吧,你可以让你的生活更轻松,并使用PHP的神奇重载__call方法来创建通用的getter和setter。您可以将以下方法添加到“数据库对象超类”:

/**
 * Create magic getter and setter methods to access private $fields array 
 */
public function __call($method, $args)
{
  $prefix = substr($method, 0, 3);
  $prop   = lcfirst(substr($method, 3));

  if (isset($this->fields[$prop])) {

    if ($prefix == 'get') {
      return $this->fields[$prop];
    } elseif ($prefix == 'set') {
      if ( ! isset($args[0])) {
        $msg = 'Missing argument: ' . get_class($this) . "::$method must specify a value";
        throw new InvalidArgumentException($msg);
      }
      $this->fields[$prop] = $args[0];
      return;
    }
  }

  $msg = 'Invalid method: ' . get_class($this) . "::$method does not exist";
  throw new BadMethodCallException($msg);
}

让我解释一下这里发生了什么。神奇的__call方法将接收对任何对象方法的调用,该方法与对象的具体方法之一不匹配。它接收作为参数的被调用方法的名称及其参数数组。

上面的__call方法会快速substr检查方法是否为“getter”或“setter”(使用方法名称的前三个字母)。它期望您的$fields数组存储小写“属性”名称(lcfirst),并使用setter / getter前缀之后的所有内容作为预期的属性名称。

如果属性与getter方法匹配,则返回该属性。如果不是,则抛出SplException BadMethodCallException。这是最佳实践,因为在PHP中包含了Spl异常。

同样,如果没有指定参数,setter方法也会抛出SplException InvalidArgumentException

PHP的神奇方法将改变你的生活。您还可以使用__get__set以类似的方式分配$fields数组值,而无需进行虚假方法调用。兴奋:)

答案 1 :(得分:1)

有两种主要方法:

创建PHP文件

我知道的所有大型ORM /数据库项目都不允许用户自己编写所有getter方法。当您调用命令行脚本时,DoctrinePropel都使用自动生成器来使用getter方法创建真正的PHP文件。这些文件包含所谓的Base方法,这些方法会由您自己编写代码的某些类自动扩展(因此基类的重新创建不会删除您自己的代码)。

文件创建的

优势是你有一个定义良好的界面(当可调用的方法在源代码中不可见时,有些人不喜欢它。)

魔术方法/重载

我在客户端的应用程序中看到的数据库引擎使用了神奇的方法模拟 getter和setter。您可以使用魔术方法__get()__set()__call()(称为“overloading” in PHP documentation)。使用哪种方法取决于您希望如何访问您的值(最常见的$obj->property$obj->getProperty())。

重载的

优点是您不需要编写复杂的PHP代码生成器,也不需要在每次更改数据库设计时调用命令行脚本。

答案 2 :(得分:0)

通过在对象上实现一些magic methods,您可以充分利用这两个方面。例如,通过实施__get__set__isset,您可以使属性访问看起来“自然”(例如$user->id),同时无需定义属性在每个单独的子类中。

例如,__get的实现可以在运行时检查$fields成员,以查看您尝试获取的属性是否对特定对象类有效。您可以在基类中编写此通用实现一次,并相应地填充$fields以使其适用于任何类型的对象。这实际上是所有现代映射工具的功能,包括您所听说过的所有PHP框架。

顺便说一句,我希望你在get_column_data内缓存每个类的表模式。每次构造相应类的对象时,为同一个表的模式重新查询数据库是非常低效的。