为什么要抽象我的数据层?

时间:2011-03-15 16:21:36

标签: php mysql oop database-abstraction

OOP原则对我来说很难掌握,因为出于某种原因我永远不会将它们应用于Web开发。随着我开发越来越多的项目,我开始理解我的代码的某些部分如何使用某些设计模式来使它们更容易阅读,重用和维护,所以我开始越来越多地使用它。

我仍然无法理解的一件事是为什么我应该抽象我的数据层。基本上,如果我需要将存储在我的数据库中的项目列表打印到浏览器,我会按照以下方式执行以下操作:

$sql = 'SELECT * FROM table WHERE type = "type1"';'
$result = mysql_query($sql);

while($row = mysql_fetch_assoc($result))
{
    echo '<li>'.$row['name'].'</li>';
}

我正在阅读所有这些How-Tos或有关PDO伟大的文章,但我不明白为什么。我似乎没有保存任何LoC,我也看不出它是如何更可重用的,因为我上面调用的所有函数似乎都被封装在一个类中但完全相同。我看到PDO的唯一优势是准备好的陈述。

我不是说数据抽象是一件坏事,我问的是这些问题,因为我正在尝试正确设计我当前的类,他们需要连接到数据库,所以我想我会这样做< em>正确的方式。也许我只是在阅读关于这个主题的不好文章:)

我真的很感激这个主题的任何建议,链接或具体的现实例子!

5 个答案:

答案 0 :(得分:3)

考虑将数据层抽象为一种节省未来时间的方法。

使用你的例子。假设您更改了表格的名称。您必须使用该表转到您拥有SQL的每个文件并进行编辑。在最好的情况下,这是一个搜索和替换N个文件的问题。如果您只需要编辑一个文件,即拥有所有sql方法的文件,那么您可以节省大量时间并最大限度地减少错误。

这同样适用于列名。

这只是考虑你重命名的情况。完全可以更改数据库系统。例如,您的SQL在Sqlite和MySQL之间可能不兼容。你必须再次编辑很多文件。

抽象允许您将一个部分与另一个部分分离。在这种情况下,您可以更改数据库部件而不影响视图部件。

对于非常小的项目,这可能比它的价值更麻烦。即便如此,你仍然应该这样做,至少要习惯它。

答案 1 :(得分:3)

我不是一个php人,但这是一个更普遍的问题,所以这里。

你可能正在构建一些小的东西,有时即使是小/中等的东西也应该有一个抽象的数据层,以便它可以更好地生长。

重点是应对 CHANGE

想想看,你有一个小型的社交网站。考虑一下您要存储的数据,个人资料详情,图片,朋友,消息。对于其中的每一个,您都会有pictures.php?&uid=xxx等页面。

然后你会用mysql代码在那里打一小段SQL。现在想想改变它有多容易/困难?你会改变5-10页?如果你这样做,你可能会在彻底测试之前多次弄错。

现在,想想Facebook。想想会有多少页面,您认为在每个页面中更改一行SQL会更容易吗?

正确抽象数据访问时:

  1. 它在一个地方,更容易改变。
  2. 因此更容易测试。
  3. 更容易更换。 (想想如果必须切换到另一个数据库,你必须做什么)
  4. 希望这有助于

答案 2 :(得分:2)

抽象数据层的另一个优点是减少对底层数据库的依赖。

使用您的方法,当您想要使用除mysql之外的其他内容或您的列命名更改或关于mysql的php API更改时,您将不得不重写大量代码。

如果所有数据库访问部分都被巧妙地抽象化,那么所需的更改将是最小的,并且仅限于几个文件而不是整个项目。

如果代码集中在一个地方,重用有关sql注入或其他实用程序函数的代码也容易得多。

最后,如果所有内容都通过某些课程而不是项目中的每个页面进行单元测试,则更容易。

例如,在我最近的一个项目中(抱歉,没有代码共享是可能的),mysql相关的函数只在一个类中调用。从查询生成到对象实例化的所有内容都在这里完成。因此,我非常适合转换到另一个数据库或在其他地方重用此类。

答案 3 :(得分:1)

在我看来,数据访问是与其他代码分离/抽象的最重要方面之一。

分离出各种“层”有几个优点。

1)它整齐地组织了你的代码库。如果您必须进行更改,您将立即知道需要进行更改的位置以及在何处查找代码。如果你自己在一个项目上工作,但是如果你拥有一个更大的团队,那么这个好处很快就会变得很明显,这可能不是什么大问题。这一点实际上是微不足道的,但无论如何我都添加了它。真正的原因是数字2 ..

2)你应该尝试将可能需要彼此独立变化的事物分开。在您的具体示例中,您可以想到在不影响用户界面的情况下更改数据库/数据访问逻辑。或者,您可能希望更改用户界面而不影响数据访问。我相信如果代码相互混合,你可以看到这是不可能的。

当您的数据访问层具有严格定义的界面时,您可以根据需要更改其内部工作方式,并且只要它仍然遵循界面,您就可以确定它不会进一步破坏任何内容。显然,这仍需要通过测试进行验证。

3)重复使用。编写数据访问代码可能会非常重复。当您必须为您编写的每个页面重写数据访问代码时,它会更加重复。每当你发现代码中出现重复的东西时,警钟就会响起。重复性很容易出错并导致维护问题。

我确定你会在各种不同的页面中看到相同的查询?这可以通过将这些查询放在数据层中来解决。这样做有助于简化维护;每当表或列名称发生更改时,您只需要更正数据层中引用它的一个位置,而不是在整个用户界面中拖网并可能遗漏某些内容。

4)测试。如果您想使用自动化工具进行单元测试,您需要将所有内容完美地分开。当此代码分散在整个界面中时,您将如何测试代码以选择所有客户记录?如果在数据访问对象上具有特定的SelectAllCustomers函数,则会容易得多。您可以在此处测试一次,并确保它适用于使用它的每个页面。

我还有更多理由让其他人加入。要带走的主要事情是分离层允许一层改变,而不会让变化波及其他层。由于数据库和用户界面是最频繁更改的应用程序/网站区域,因此将它们与其他所有内容完全隔离并保持隔离是一个非常好的主意。

答案 4 :(得分:0)

在我看来只打印数据库表中的项目列表时,您的代码段更合适:快速,简单和清晰。

我认为有点更多的抽象在其他情况下可能有所帮助,以避免代码重复具有所有相关优势。

考虑一个简单的CMS,其中包含作者,文章,标签以及文章和标签的交叉参考表。

在您的主页中,您的简单查询将变得更加复杂。您将加入文章和用户,然后您将为每个使用交叉引用加入标签表并通过article_id过滤的文章获取相关标签。

您将通过作者个人资料和代码搜索结果中的一些小更改重复此查询。

使用抽象工具like this,您可以定义一次关系,并使用更简洁的语法,如:

// Home page
$articles = $db->getTable('Article')->join('Author a')
    ->addSelect('a.name AS author_name');
$first_article_tags = $articles[0]->getRelated('Tag');

// Author profile
$articles = $db->getTable('Article')->join('Author a')
    ->addSelect('a.name AS author_name')->where('a.id = ?', $_GET['id']);

// Tag search results
$articles = $db->getTable('Article')->join('Author a')
    ->addSelect('a.name AS author_name')
    ->join('Tag')->where('Tag.slug = ?', $_GET['slug']);

您可以减少在模型中封装它的剩余代码重复并重构上面的代码:

// Home page
$articles = Author::getArticles();
$first_article_tags = $articles[0]->getRelated('Tag');

// Author profile
$articles = Author::getArticles()->where('a.id = ?', $_GET['id']);

// Tag search results
$articles = Author::getArticles()
    ->join('Tag')->where('Tag.slug = ?', $_GET['slug']);

还有其他充分的理由来抽象或多或少地抽象,其优点和缺点。但在我看来,网络项目的重要部分主要是这一个:P