首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

MongoDB PHP Table 類別實作分析:Config 連線管理、Cursor 遊標獲取、find/look/getCursor 三種查詢模式差異

     編輯:PHP 綜合知識

本文分析一個基於 Zend Framework 風格的 MongoDB PHP 封裝類別:Hrs_Mongo_Config 管理連線與資料庫選擇,Hrs_Mongo_Table 提供 CRUD 與三種查詢介面 (find/look/getCursor),詳細說明遊標物件、陣列轉換、連線狀態檢查機制。

Config 類別:連線管理

<?php
class Hrs_Mongo_Config {
    const DEFAULT_HOST = 'localhost';
    const DEFAULT_PORT = 27017;
    private static $host = self::DEFAULT_HOST;
    private static $port = self::DEFAULT_PORT;
    private static $options = [
        'connect' => true,
        'timeout' => 30,
        // 'replicaSet' => ''
    ];
    public static $conn = null;
    public static $defaultDb = null;
    public static $linkStatus = '';

    public static function set($server = 'mongodb://localhost:27017', $options = ['connect' => true]) {
        // 解析 $server (字串或陣列),建構連線 URI
        // 支援認證:mongodb://user:pass@host:port
        $url = ...; 
        
        if (is_array($options)) {
            foreach (self::$options as $k => $v) {
                if (isset($options[$k])) self::$options[$k] = $options[$k];
            }
        }
        
        try {
            self::$conn = new Mongo($url, self::$options); // 舊版 Mongo 驅動
            self::$linkStatus = 'success';
        } catch (Exception $e) {
            self::$linkStatus = 'failed';
        }
        
        if (isset($server['database'])) {
            self::selectDB($server['database']);
        }
    }

    public static function selectDB($database) {
        if (!$database) throw new Zend_Exception('Database name required');
        if (self::$linkStatus !== 'success') throw new Zend_Exception('Connection failed');
        self::$defaultDb = self::$conn->selectDB($database);
        return self::$defaultDb;
    }
}

Table 類別:核心操作

<?php
abstract class Hrs_Mongo_Table {
    protected $_db = '';        // MongoCollection 物件
    protected $_name = '';      // 集合名稱
    protected $_data = [];      // find() 結果暫存
    protected $c_options = ['fsync'=>true, 'safe'=>true];
    protected $u_options = ['multiple'=>true, 'fsync'=>true, 'safe'=>true];
    protected $d_options = ['fsync'=>true, 'justOne'=>false, 'safe'=>true];

    public function __construct() {
        if (Hrs_Mongo_Config::$conn instanceof Mongo) {
            $this->_db = Hrs_Mongo_Config::$defaultDb->{$this->_name};
        } else {
            throw new Zend_Exception('Mongo connection failed');
        }
    }

    // 基本 CRUD
    public function insert($data) { return $this->_db->insert($data, $this->c_options); }
    public function update($data, $where) { return $this->_db->update($where, $data, $this->u_options); }
    public function delete($where) { return $this->_db->remove($where, $this->d_options); }
    public function dropMe() { return $this->_db->drop(); }

    // 查詢模式一:find() 回傳 $this,結果存 $_data,稍後 toArray()
    public function find($where = [], $limit = 0) {
        if ($this->testLink()) {
            $cursor = $where ? $this->_db->find($where) : $this->_db->find();
            if ($limit > 0) $cursor->limit($limit);
            $cursor->snapshot(); // 防止重複/遺漏
            $this->_data = $cursor;
        }
        return $this; // 鏈式呼叫
    }

    // 查詢模式二:look() 直接回傳 MongoCursor 遊標物件
    public function look($where = [], $fields = []) {
        if (!$this->testLink()) return false;
        if ($fields) {
            return $where 
                ? $this->_db->find($where, $fields) 
                : $this->_db->find()->fields($fields);
        }
        return $where ? $this->_db->find($where) : $this->_db->find();
    }

    // 取得 find() 存儲的遊標
    public function getCursor() {
        return $this->_data;
    }

    // 結果轉換
    public function toArray() {
        $result = [];
        foreach ($this->_data as $id => $row) {
            $row['_id'] = $id;
            $result[] = $row;
        }
        return $result;
    }

    public function __toString() {
        return (string)$this->_data;
    }

    protected function testLink() {
        return Hrs_Mongo_Config::$linkStatus === 'success';
    }
}

三種查詢模式差異總結

方法回傳值結果儲存適用場景記憶體
find()$this (鏈式)存入 $_data (MongoCursor)後續呼叫 toArray() 取得完整陣列一次性載入全部
look()MongoCursor不儲存,直接回傳需自行迭代、大量資料分批處理逐筆迭代,省記憶體
getCursor()MongoCursor從 $_data 取出find() 後需直接操作遊標同上

使用範例

<?php
// 定義具體 Table
class UserTable extends Hrs_Mongo_Table {
    protected $_name = 'users';
}

// 初始化連線
Hrs_Mongo_Config::set([
    'host' => 'localhost',
    'port' => 27017,
    'database' => 'myapp',
    'user' => 'admin',
    'pass' => 'secret'
]);

$userTable = new UserTable();

// 模式一:find() + toArray() (小資料集)
$users = $userTable->find(['status' => 1], 20)->toArray();
foreach ($users as $u) { echo $u['name'] . "\n"; }

// 模式二:look() 直接迭代遊標 (大資料集)
$cursor = $userTable->look(['status' => 1], ['name' => 1, 'email' => 1]);
foreach ($cursor as $doc) {
    // 逐筆處理,不佔用大量記憶體
    process_user($doc);
}

// 模式三:find() 後 getCursor() 取得遊標
$userTable->find(['status' => 1]);
$cursor = $userTable->getCursor();
$cursor->sort(['created_at' => -1]);
foreach ($cursor as $doc) { ... }

重要注意事項

  • 驅動版本: 程式碼使用舊版 Mongo 類別 (PECL mongo),現代專案請改用 MongoDB\Driver\Manager (mongodb 擴充套件) 或官方 mongodb/mongodb 程式庫。
  • snapshot(): 確保查詢過程中資料不重複/不遺漏,但會增加伺服器負擔,大集合慎用。
  • fields 投影: look($where, ['name'=>1]) 僅取回需要欄位,大幅減少網路傳輸。
  • _id 處理: toArray() 會將 _id 併入陣列,方便後續操作。
  • 連線複用: Hrs_Mongo_Config::$conn 為靜態單例,全程複用同一連線。

現代寫法對照 (mongodb/mongodb 程式庫)

<?php
require 'vendor/autoload.php';
$client = new MongoDB\Client("mongodb://localhost:27017");
$collection = $client->myapp->users;

// 等同 find() + toArray()
$users = $collection->find(['status' => 1], ['limit' => 20])->toArray();

// 等同 look() 迭代
$cursor = $collection->find(['status' => 1], ['projection' => ['name' => 1, 'email' => 1]]);
foreach ($cursor as $doc) { ... }

// 遊標方法豐富:sort, limit, skip, batchSize, hint, explain 等
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved