3

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

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

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

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

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

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

我非常感谢任何关于该主题的建议、链接或具体的现实生活示例!

4

5 回答 5

3

将数据层抽象为将来节省时间的一种方式。

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

这同样适用于列名。

这仅考虑您重命名内容的情况。完全改变数据库系统也是完全可能的。例如,您的 SQL 可能在 Sqlite 和 MySQL 之间不兼容。您将不得不再次编辑大量文件。

抽象允许您将一个部分与另一部分解耦。在这种情况下,您可以在不影响视图部分的情况下对数据库部分进行更改。

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

于 2011-03-15T16:30:12.980 回答
3

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

您可能正在构建一些小型的东西,有时即使是小型/中型的东西也应该有一个抽象的数据层,这样它才能变得更好。

关键是应对变化

想想看,你有一个小型社交网站。想想您将存储的数据、个人资料详细信息、图片、朋友、消息。对于其中的每一个,您将拥有类似pictures.php?&uid=xxx.

然后,您将使用 mysql 代码在其中插入一小段 SQL。现在想想改变这一点有多容易/多难?你会改变5-10页?当你这样做时,你可能会在彻底测试之前弄错几次。

现在,想想 Facebook。想想会有多少页,你觉得每页一行SQL会更容易吗!?

当您正确抽象数据访问时:

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

希望这可以帮助

于 2011-03-15T16:30:37.333 回答
2

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

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

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

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

最后,如果所有内容都通过某些类进行,而不是在项目的每个页面上进行,那么进行单元测试会更容易。

比如我最近的一个项目中(抱歉,不能共享代码),mysql相关函数只在一个类中调用。从查询生成到对象实例化的一切都在这里完成。所以对我来说改变到另一个数据库或在其他地方重用这个类是非常好的。

于 2011-03-15T16:30:52.870 回答
1

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

分离出不同的“层”有几个优点。

1)它整齐地组织你的代码库。如果您必须进行更改,您将立即知道需要在哪里进行更改以及在哪里可以找到代码。如果您自己处理一个项目,这可能没什么大不了的,但是如果团队更大,好处很快就会变得明显。这一点实际上是微不足道的,但我还是添加了它。真正的原因是2号..

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

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

3) 重用。编写数据访问代码可能会变得非常重复。当您必须为您编写的每个页面重写数据访问代码时,它甚至更加重复。每当您注意到代码中有重复内容时,警钟就应该响起。重复性,容易出错并导致维护问题。

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

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

还有更多的原因我会让其他人补充。最主要的是,分离层允许一个层进行更改,而不会让更改波及其他层。由于数据库和用户界面是应用程序/网站中更改最频繁的区域,因此将它们分开并与其他所有内容以及彼此很好地隔离是一个非常好的主意。

于 2011-03-15T16:52:13.907 回答
0

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

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

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

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

您将重复此查询,并在作者简介和标签搜索结果中进行一些小的更改。

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

// 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

于 2011-03-16T00:06:45.127 回答