动态创建数据库模型类

时间:2011-08-02 20:05:54

标签: php database oop database-design

我正在尝试在我构建的轻型框架中改进我用于数据库事务的方法。

了解问题的信息:

这是我编写的一个类(其中connect.php加载数据库凭据; PHP PDO的包装器,存储在$db;以及Base.php):

<?php
    require_once('connect.php');

    class Advertiser extends Base
    {
        public static function getByID($id)
        {
            global $db;
            $sql = "SELECT * FROM advertiser WHERE advertiserid=?";
            $values = array($id);
            $res = $db->qwv($sql, $values);

            return Advertiser::wrap($res);
        }

        public static function add($name)
        {
            $adv = new Advertiser(null, $name);
            $res = $adv->save();

            return $res;
        }

        public static function wrap($advs)
        {
            $advList = array();
            foreach( $advs as $adv )
            {
                array_push($advList, new Advertiser($adv['advertiserid'], $adv['name']));
            }

            return Advertiser::sendback($advList);
        }

        private $advertiserid;
        private $name;

        public function __construct($advertiserid, $name)
        {
            $this->advertiserid = $advertiserid;
            $this->name = $name;
        }

        public function __get($var)
        {
            return $this->$var;         
        }

        public function save()
        {
            global $db;
            if( !isset($this->advertiserid) )
            {
                $sql = "INSERT INTO advertisers (name) VALUES(?)";
                $values = array($this->name);
                $db->qwv($sql, $values);

                if( $db->stat() )
                {
                    $this->advertiserid = $db->last();
                    return $this;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                $sql = "UPDATE advertisers SET name=? WHERE advertiserid=?";
                $values = array ($this->name, $this->advertiserid);
                $db->qwv($sql, $values);

                return $db->stat();
            }
        }
    }
?>

正如您所看到的,它具有相当标准的CRUD功能(编辑:好的,所以在此实现中只有CRU)。有时,我会通过添加更多函数来扩展这样的类,这就是这些类的用途。例如,我可能会将以下函数添加到此类中(假设我向数据库添加了一个列isBanned):

public static function getBanned()
{
    global $db;
    $sql = "SELECT * FROM advertiser WHERE isBanned=1";
    $res = $db->q($sql);

    return Advertiser::wrap($res);
}

问题:

如何创建一个catchall类,它还会在存在且必要时加载自定义模型类?

例如,如果我编写以下代码:

$model = new Catchall();
$banned = $model->Advertiser::getByID(4);

我希望我的catchall类可以修改它的查询,以便对表/列的所有引用都是我选择的名称(在这种情况下为Advertiser),但是小写。

另外,如果我想创建一个像我上面写的那样的自定义函数,我希望我的catchall类能够确定一个文件存在于其路径中(当然是先前定义的),其名称是我的指定(在这种情况下为Advertisers.php)并加载它。

Advertisers.phpextends Catchall并且仅包含我的自定义函数。

通过这种方式,我可以拥有一个适用于所有CRUD函数的Catchall类,并且可以根据需要轻松扩展任意类。

  1. 我需要了解哪些想法/概念?
  2. 我在哪里可以找到这方面的例子,没有挖掘大量的CodeIgniter或Zend源代码
  3. 我正在尝试做什么名为

3 个答案:

答案 0 :(得分:3)

一般资料:我会查看Doctrine2有关如何在PHP中创建ORM的示例。他们使用标记语言中的映射来表示:此表包含此类型的这些列。此外,虽然不是在PHP中,Django ORM非常易于使用和理解,并且通过该教程大约20分钟左右,这将真正让您看到一些简洁的可能性。 (它对我有用)

快速搜索“php active record lightweight”返回了几个有趣的例子,可能会让你走上正确的道路。

PHP创意:我会调查php,__ GET和__SET中的魔术getter和setter,它可以让你在对象上设置值,而不必为每个字段设置一个getter / setter表。您可以创建一个__SET,以确保set字段是该表中的字段,并在下次保存该对象时将其添加到“要更新的字段”列表中。但是,从长远来看,这不是一个好主意,因为它很快失控,而且很脆弱。

建议:最后,我在一家使用看起来几乎完全相同的系统的公司工作,我可以毫不含糊地说,你不想尝试扩展这个长期。像这样的系统(活动记录模式)可以预先节省大量的时间,不必编写查询和事物,但如果您想要开始单元测试业务逻辑,可能会花费很多时间。 对象类。

例如,不可能模拟/依赖注入静态GetById方法(它基本上是一个全局方法),因此每次在代码中调用时,代码将转到真实数据库并返回一个真实对象。这样的编码并不需要太多,以使系统几乎不可能测试,咆哮并紧密耦合到数据库。

虽然它们的执行速度可能比上面的代码慢一些,但如果您计划在相当长的时间内使用它,请尝试查看ORM工具。

编辑这称为活动记录。

答案 1 :(得分:1)

您尝试做的事情有几种不同的设计模式。查看Data MapperActive Record

答案 2 :(得分:0)

使用PHP的“魔术方法”__get,当您通过以下方式访问它时,可以生成此功能:

$model = new Catchall();
$banned = $model->Advertiser->getByID(4);

...它将a)检查是否已定义类Advertiser,b)检查名为Advertiser.php的文件并包含它,或c)返回一个新的实例泛类。

您在::示例中使用的语法假定返回的类是静态的。我没有编写这个代码来解决这个问题,但这样做应该是微不足道的。

请参阅文档:http://www.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.methods

快速而肮脏的例子:

    public function __get($name) {

            $instance = false;
            // see if there is already a class with the requested name
            if (class_exists($name)) {
                $instance = new $name();
            }

            // check to see if there is an object def for the requested object
            if ($instance === false && file_exists(PATH_TO_OBJECTS.$name.'.php')) {
                require_once(PATH_TO_OBJECTS.$name.'.php');
                $instance = new $name();
            }

            // if instace is still not found, load up a generic
            if ($instance === false)
                $instance = new Catchall($name);

        return $instance;
    }