CRUD和OOD.怎么解决这个问题?

drw*_*www 5 php mysql oop crud

请务必诚实,如果必须,请撕开我的工作.

所以我正在重写我最近制作的一个小型网络应用程序.原因很简单,代码变得非常混乱,我想学习并应用更好的OO设计.这个应用程序应该做的只是简单的CRUD.我有一个包含3个表的数据库,它们彼此无关,companies并且与公司和合作伙伴有1:n​​的关系.很简单,真的.现在,我有几个问题,我将在帖子的最后说明.在这里,我将尝试解释:partnerscity

我的第一个方法是创建类公司,合作伙伴和城市,从数据库中获取所有数据集并从中创建对象:

class company {

    private $id   = null;
    private $name = null;
    private $city = null;

    //many more attributes

    function __construct( $id, $name, $city, [...] ) {

        $this->id   = $id;
        $this->name = $name;
        $this->city = $city;

        //huge constructor
    }

   /*
    *  getters + setters here
    *
    *  no need to paste the partner class as it looks just like this one
    *
    */
}
Run Code Online (Sandbox Code Playgroud)

这就是所有这些课程.我拿来从数据库和建造公司,合作伙伴和城市每一个对象的数据集(这些类中的属性城市是几个属性本身就是一个对象),并将它们保存到两个数组arr_companiesarr_partners,然后持有这些对象......它工作得很好像那样.

现在,我想要的是更新,插入,删除数据库,并且所有3个类(城市,公司,合作伙伴)都需要此功能.我的方法是我创建了一个带有构造函数的新类,该构造函数基本上采用2个字符串命令和对象,例如('update', 'company'),然后它将直接在数据库中更新公司,使我的对象不受影响.这让我很伤心,因为我有很好的构造对象,我不知道如何利用它们.

问题:

  • 拥有如此庞大的构造函数(我最大的构造函数需要28个参数)是不是很糟糕?

  • 你是否应该有一个单独的数据库操作类,或者最好是为它创建一个抽象类或接口,让子类本身处理更新,删除,插入?

  • 只要编写,从数据库中删除,只要我应该将这些更改应用于我的对象并且稍后只执行命令到数据库,例如会话结束时,这是常见的吗?

  • 我认为像这样的应用程序必须在幻想时代完成.这里适当的方法是什么?创建对象,使用对象,将它们保存到数据库中?

  • 我有很多问题,但我想很多问题我只是不知道该怎么问.

请注意,如果可能的话,我现在不想使用ORM.

非常感谢您的宝贵时间.

Mik*_*ell 6

OP中提出的问题:

"拥有如此庞大的构造函数(我最大的构造函数需要28个参数)是不是很糟糕"?

  • 是.想象一下调用代码.您必须传递28个不同的值,更不用说每个调用都必须遵守构造函数中指定的确切顺序.如果一个参数不合适,您可能会破坏参数依赖算法的破坏.如果你真的需要传递大量参数,我建议将它们作为一个数组传递(将一个例子发布到另一个SO问题).

"你是否应该有一个单独的数据库操作类,或者最好是为它创建一个抽象类或接口,让子类本身处理更新,删除,插入?"

  • 一般来说,在创建课程时,您希望尝试识别最能代表您的业务需求的名词.在您的具体情况下,您可能会有三个班级; 公司,合作伙伴和城市.

  • 现在在每个类(名词)中,你的方法将采用动词的形式,因此在语法上你的调用代码是有意义的: if ($company->getName() === 'forbes')

  • 正如您所提到的,每个类都需要一个数据库对象(dbo)来使用,因此您可以实现任意数量的模式来公开与类的数据连接; 单身,单身与工厂或依赖注入等

  • 抽象(父)类非常适合跨子类共享通用算法,并且应该在您处于设计的伪代码阶段时进行标识.父类还允许您通过在父级中声明抽象方法来强制子类具有方法.

  • 接口在某些情况下是一个有用的工具,但我发现它们不如在父类中声明抽象方法那么灵活.但是在类不共享父母的情况下,这种情况很好.

"只要编写,从数据库中删除,只要或者我应该将这些更改应用于我的对象并且稍后只执行命令到数据库,例如当会话结束时"?

  • CRUD活动应该在执行操作时发生.如果您等待会话结束,则可能会遇到由于用户关闭浏览器而导致会话过早结束的情况.为了更好地保护您的数据,您可以将CRUD活动包装在事务中.

  • 如果您正在运行高流量应用程序,则可以实施排队系统并排队要完成的工作.

"我认为像这样的应用程序必须在以前完成幻想.这里适当的方法是什么?创建对象,使用对象,将它们保存到数据库中"?

  • 你是对的,这是以前做过的,通常被称为ORM(对象关系映射器).基本上,ORM会自省数据库模式,并创建表示模式的对象(和关系).因此,您不使用本机SQL,而是使用对象.虽然您可以将SQL用于自定义业务需求,但在Doctrine的情况下,您将使用Doctrine查询语言(DQL)与本机SQL.

  • 我强烈推荐的ORM是Doctrine.

如果您不想使用ORM,可以将CRUD方法添加到主类.我选择了一个接口,因此您的类不必从包含数据库操作的父级扩展.另外,请查看这篇文章,了解如何使用singleton/factory公开类数据库对象.

考虑以下:

// Company.php
class Company implements iDatabaseOperation

    public function delete()
    {
        // Lets use a DBO singleton/factory for DB access
        //   Uses PDO, which is strongly recommended
        $dbo = Database::factory(Database::DATABASE_NAME);

        $dbo->beginTransaction();

        try {

            $sql = 
                "DELETE FROM " .
                "    company " .
                "WHERE " .
                "    id = :companyId " .
                "LIMIT 1";

            $stmt = $dbo->prepare($sql);

            $stmt->bindValue(':companyId', $this->getId());

            $stmt->execute();

            $dbo->commit();

        } catch (Exception $e) {

            $dbo->rollback();

            error_log($e->getMessage();

            $e = null; // Php's garbage collection sucks
        }
    }
}

// iDatabaseOperation.php
interface iDatabaseOperation
{
    public function delete();
    public function update();
    public function insert();
}
Run Code Online (Sandbox Code Playgroud)