這個問題是相當開放的,所以我會給出一個相當廣泛的答案,並儘量不要太過分。我會首先說ORM解決方案像Doctrine's,Propel's或Symfony's可能是管理關係對象最理想的方法,但對於快速或乾淨地實現並不總是切實可行的(可能需要一段時間才能學習ORM,然後轉換現有的代碼)。這是我採取更輕量化的方法。
首先,它可能有助於將數據庫查詢從類構造函數中提取出來,以便您可以更好地控制訪問數據庫的時間。一種策略是將靜態方法添加到您的類中以獲取結果。另外,您可以提供選項來「預取」子對象,以便可以批量執行查詢。因此,要進入你的例子中,外部API會是這個樣子:
$orders = Order::getOrders(array(
'items' => true
));
這裏的想法是要拿到訂單的陣列與getOrders()
方法,並告訴getOrders()
獲取item
子對象的同時。從Order
課程以外,這非常簡單:只需傳入一個'items'
密鑰設置爲true
即可。然後Order
類中:
class Order
{
public $items = null;
public static function getOrders(array $options = array())
{
$orders = array();
$result = mysql_query("SELECT DISTINCT id FROM orders WHERE customer = 1234 LIMIT 50");
while ($row = mysql_fetch_array($result, MYSQL_NUM)) {
$order = new Order($row);
$orders[$order->id] = $order;
}
// if we're asked to fetch items, fetch them in bulk
if (isset($options['items']) && $options['items'] === true) {
$this->items = array();
$items = Item::getItemsForOrders($orders);
foreach ($items as $item) {
$orders[$item->orderId]->items[] = $items;
}
}
return $orders
}
public function __construct(array $data = array())
{
// set up your object using the provided data
// rather than fetching from the database
// ...
}
public function getItems()
{
if ($this->items === null) {
$this->items = Item::getItemsForOrders(array($this))
}
return $items;
}
}
而在你Item
類:現在
class Item
{
public $orderId = null;
public static function getItemsForOrders(array $orders, array $options = array())
{
// perform query for ALL orders at once using
// an IN statement, returning an array of Item objects
// ...
}
}
,如果你知道你需要的物品,當你得到你的訂單,通過在true
爲'items'
選項:
$orders = Order::getOrders(array(
'items' => true
));
或者,如果你不需要的東西,不指定任何:
$orders = Order::getOrders();
不管怎樣,當你通過你的命令循環,該API是訪問項目相同:
// the following will perform only 2 database queries
$orders = Order::getOrders(array(
'items' => true
));
foreach ($orders as $order) {
$items = $order->getItems();
}
// the following will perform 1 query for orders
// plus 1 query for every order
$orders = Order::getOrders();
foreach ($orders as $order) {
$items = $order->getItems();
}
正如你所看到的,提供'items'
選項可以導致更有效地使用數據庫,但如果你只需要orders
而不是在items
左右,你也可以這樣做。
而且因爲我們要getOrders()
提供一組選項中,我們可以很容易地擴展我們的功能,包括標記爲其他子對象(或其他任何東西,應該是「可選」):
$orders = Order::getOrders(array(
'items' => true,
'tags' => true,
'widgets' => true,
'limit' => 50,
'page' => 1
));
...你如果需要,可以代理到子對象的選擇:
// ...
// in the `Order::getOrders()` method, when getting items...
$items = Item::getItemsForOrders($orders, array(
'tags' => (isset($options['tags']) && $options['tags'] === true)
));
如果你不是明智的什麼應該或不應該是可選的獲取對象時,這種方法可以變得臃腫和艱鉅的維護,但如果你保持你的API簡單,只在需要時進行優化,它可以非常好地工作。希望這可以幫助。
這正是我所期待的!我已經開始按照您的建議重新組織我的課程,並且我能夠使用您的概念將更大的靈活性與更快的結果結合起來。使用你在這裏提出的建議,我不僅傳遞了選項,比如是否要加載項目,還傳遞了其他選項以各種方式過濾主要getOrders()查詢。幾乎正是我所期待的。非常感謝! – user2702162
很高興能幫到你! – Divey