PHP:保持对象分离?

标签 php mysql

我正在用 PHP 开发一个复杂的项目,但一直遇到同样的问题:如何将单独的对象分开?

面向对象编程背后的思想是,任何对象都不需要知道任何其他对象的内部工作方式。但是对于第三个普通数据库,所有内容都在一个单独的表中,并且所有表都是相互关联的。

假设我有几个对象。 Order 对象(带有 Order 类和几个 Order 相关的数据库表)、带有 Address Class 和 Address 表的 Address 对象)、Items(表和类)和 Customers(表和类)。

许多任务(例如运送订单)需要来自上述所有表的数据,并且所有数据都通过外键互连。那么,在不使代码成为灾难或违反 OO 原则的情况下,加载所有所需对象/数据的最优雅/最有效的方法是什么?

方法 A: 一个类执行单个查询并将其他类加载到自身中。

class Order {

   public function LoadFromID($OrderID)
   {
      SELECT * FROM Orders
      LEFT JOIN Customers
      LEFT JOIN Addresses
      LEFT JOIN Items

      $this->oCustomer = new Customer();
      $this->oCustomer->SetName($W->CustomerName);

      $this->oAddress = new Address();
      $this->oAddress->SetCity($W->City);

      $this->oaItems = array();
      foreach($w->Items AS $Item)
      {
         $oItem = new Item();
         $oItem->SetName($Item->ItemName);
         $this->oaItems[] = $oItem;
      }
   }
}

问题是 Order 类需要了解 Customers、Items 和 Addresses 表的布局方式。如果我们想走另一条路,让地址对象找到附加到它的订单和供应商怎么办?因为一切都是相互关联的,所以每个对象都需要知道每个其他对象的表是如何构建的。这意味着如果您想向表中添加新字段,则必须在每个对象中查找和编辑这些查询。这造成了巨大的维护问题。

方法 B: 一个类实例化自己并指示其他类在其内部实例化自己。

class Order {

   public function LoadFromID($OrderID)
   {
      SELECT * FROM Orders
      $W = mysql_row();

      // A customer object is instantated and passed
      // a customer ID to load from.
      $this->oCustomer = new Customer($W->CustomerID); 
      $this->oShipAddress = new Address($W->ShipAddressID);
      $this->oBillAddress = new Address($W->BillAddressID);

      $this->oaItems = array();
      foreach($w->Items AS $Item)
      {
         $this->oaItems[] = new Item($Item->ItemID);
      }
   }
}

class Customer{
   public function __construct($CustID)
   {
      SELECT * FROM Customers WHERE $CustID;
      $W = mysql_row();

      $this->CustomerName = $W->Name;
      ...
   }
}

这种方法使对象保持分离,只有一个类可以访问它自己的表,但引入了新的问题。首先,从 MySQL 的角度来看,它效率低下,需要执行许多查询才能获得所有需要的数据。不确定性能是否可以忽略不计。此外,一个对象永远不知道它是由 Controller 还是另一个对象创建的,因为对象可以在任何地方生成。当您需要使用围绕多个对象执行多个操作的事务时,这尤其成问题。 “开始”和“提交”的调用在哪里?作为一个对象,我是否已经在交易中,或者我需要自己开始交易?当方法用于多个特定任务时,这种不一致可能会发生冲突。有时一个方法需要创建事务,有时它已经在其中。

方法 C: Controller 实例化所有对象。

class Controller {

   public function DoSomething()
   {
      $DB->Begin();
      $oOrder=new Order();
      $aAddressIDs = $oOrder->GetAddressIDs();
      $CustomerID = $oOrder->GetCustomerID();

      foreach($aAddressIDs AS $ID)
      {
         // Take the order's address IDs 
         // and turn them into adress objects then 
         // pass them back to the order.
         $oAddress = new Address($ID);
         $oOrder->AddAddress($oAddress);
      }

      // Create a customer ID for the order
      // and pass the built object back into the order.
      $oCustomer = new Customer($CustomerID);
      $oOrder->AddCustomer($oCustomer);

      if($oOrder->DoSomethingComplex())
         $DB->Commit();
      else
         $DB->Rollback();
   }
}

这解决了有关启动和完成数据库事务的一致性问题,方法是将它们放在对象之外。此外,不会混淆对象的实例化位置,因为所有对象都必须由 Controller 创建。但这看起来真的很草率,并且需要每个 Controller 方法都知道 Order 对象需要什么才能运行。

有什么干净的方法可以做到这一点吗?

最佳答案

抱歉,您掉进了一个众所周知的陷阱。
对象不应镜像数据库。 订单对象需要获取所有相关数据,才能将订单处理到自己身上。
他绝对可以使用其他类/对象(一个树对象来正确排序订单项目,一个数据库连接类,一个 Sql 抽象类等)
如果可以,您应该在一次查询中加载数据。不是每个表一个查询。
如果您想采用每个数据源一个查询的范例,我会说关系数据库不是您想要的,而是 NoSQL 数据库(例如 MongoDB),但是同样,您将只需要使用一个对象来处理订单,因为 MongoDB 几乎强制执行了这一点。

关于PHP:保持对象分离?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6604774/

相关文章:

mysql - 选择特定字段没有其他记录的行

mysql - 如果最终依赖于操作系统,数据库如何保证持久性?

mysql - 使用准备好的语句和变量的 SQL 语法错误

mysql - 将 CSV 导入到 MySQL,其列数少于目标表

php - PHP 函数 'mysql_fetch_Assoc' 的错误结果

php - 不能从交互式 shell 中要求 mage.php

php - 空格后不允许有字符。使用 PHP 插入 MySQL

javascript - 如何解决双引号内双引号语法错误

php 无法在 Linux 服务器上的 mysql 查询中使用撇号

php - 内容类型 'text/xml; charset=utf-8' 不是预期的类型 'application/soap+xml; charset=utf-8'