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

PHP 流包裝器實作指南:php_stream_ops、php_stream_wrapper_ops 結構與自定義包裝器開發

     編輯:PHP 綜合知識

PHP 流抽象層核心在於 php_stream_ops (流操作虛表) 與 php_stream_wrapper_ops (包裝器操作虛表)。本文深入剖析兩結構體、標準 I/O 與 zlib 流實作對比、自定義包裝器開發流程。

php_stream 核心結構

typedef struct _php_stream {
    php_stream_ops *ops;        // 虛表:實際操作函式指標
    void *abstract;             // 便利指標:儲存具體資料 (如 FILE*, gzFile)
    // ... 其他欄位 (位置、狀態、快取、鎖等)
} php_stream;

php_stream_ops 虛表詳解

typedef struct _php_stream_ops {
    size_t (*write)(php_stream *stream, const char *buf, size_t count TSRMLS_DC);
    size_t (*read)(php_stream *stream, char *buf, size_t count TSRMLS_DC);
    int (*close)(php_stream *stream, int close_handle TSRMLS_DC);
    int (*flush)(php_stream *stream TSRMLS_DC);
    const char *label;           // 除錯標籤
    int (*seek)(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC);
    int (*cast)(php_stream *stream, int castas, void **ret TSRMLS_DC); // 轉換為 stdio/posix
    int (*stat)(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC);
    int (*set_option)(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC);
} php_stream_ops;

標準 I/O 流 vs zlib 流實作對比

標準 I/O (php_stdio_ops)

// 讀取實作
size_t php_stdio_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) {
    php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
    return read(data->fd, buf, count); // POSIX read()
}

// abstract 結構
typedef struct {
    int fd;           // 檔案描述符
    FILE *file;       // stdio FILE*
    // ...
} php_stdio_stream_data;

zlib 壓縮流 (php_zlib_ops)

// 讀取實作
size_t php_zlib_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) {
    struct php_gz_stream_data_t *data = (struct php_gz_stream_data_t*)stream->abstract;
    return gzread(data->gz_file, buf, count); // zlib gzread()
}

// abstract 結構
typedef struct {
    gzFile gz_file;   // zlib 壓縮檔案句柄
    // ...
} php_gz_stream_data_t;

關鍵觀察

  • ops 函式為底層 I/O 的**薄封裝** (Thin Wrapper)。
  • stream->abstract 儲存具體實作所需上下文 (fd、gzFile、SSL* 等)。
  • 統一介面隱藏底層差異:上層呼叫 php_stream_read() → 派發至 stream->ops->read()。

php_stream_wrapper_ops:包裝器操作虛表

typedef struct _php_stream_wrapper_ops {
    // 核心:開啟流
    php_stream *(*stream_opener)(php_stream_wrapper *wrapper,
        char *filename, char *mode, int options,
        char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC);
    
    // 關閉流
    int (*stream_closer)(php_stream_wrapper *wrapper, php_stream *stream TSRMLS_DC);
    
    // 流 stat
    int (*stream_stat)(php_stream_wrapper *wrapper, php_stream *stream,
        php_stream_statbuf *ssb TSRMLS_DC);
    
    // URL stat (不開啟流)
    int (*url_stat)(php_stream_wrapper *wrapper, char *url, int flags,
        php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC);
    
    // 目錄開啟
    php_stream *(*dir_opener)(php_stream_wrapper *wrapper,
        char *filename, char *mode, int options,
        char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC);
    
    const char *label;
    
    // 檔案系統操作
    int (*unlink)(php_stream_wrapper *wrapper, char *url, int options,
        php_stream_context *context TSRMLS_DC);
    int (*rename)(php_stream_wrapper *wrapper, char *url_from, char *url_to,
        int options, php_stream_context *context TSRMLS_DC);
    int (*stream_mkdir)(php_stream_wrapper *wrapper, char *url, int mode,
        int options, php_stream_context *context TSRMLS_DC);
    int (*stream_rmdir)(php_stream_wrapper *wrapper, char *url, int options,
        php_stream_context *context TSRMLS_DC);
} php_stream_wrapper_ops;

自定義包裝器開發流程

  1. 定義 php_stream_ops 實作讀/寫/關閉/Seek 等。
  2. 定義 php_stream_wrapper_ops 實作 stream_opener (建立 stream、設定 ops/abstract)。
  3. 定義 php_stream_wrapper 結合 wrapper_ops、scheme 名稱、是否為 URL 包裝器。
  4. MINIT 中呼叫 php_register_url_stream_wrapper("scheme", &wrapper) 註冊。
  5. MSHUTDOWN 中呼叫 php_unregister_url_stream_wrapper("scheme") 註銷。

最小包裝器範例:memory:// (記憶體流)

// 1. 定義 abstract 結構
typedef struct {
    char *data;
    size_t size;
    size_t pos;
} php_memory_stream_data;

// 2. 實作 ops
static size_t php_memory_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) {
    php_memory_stream_data *data = (php_memory_stream_data*)stream->abstract;
    size_t avail = data->size - data->pos;
    if (count > avail) count = avail;
    if (count > 0) {
        memcpy(buf, data->data + data->pos, count);
        data->pos += count;
    }
    return count;
}

static int php_memory_close(php_stream *stream, int close_handle TSRMLS_DC) {
    php_memory_stream_data *data = (php_memory_stream_data*)stream->abstract;
    if (data->data) efree(data->data);
    efree(data);
    return 0;
}

static php_stream_ops php_memory_ops = {
    .write = NULL, // 唯讀範例
    .read = php_memory_read,
    .close = php_memory_close,
    .flush = NULL,
    .label = "memory",
    .seek = NULL,
    .cast = NULL,
    .stat = NULL,
    .set_option = NULL
};

// 3. 實作 wrapper_opener
static php_stream *php_memory_stream_opener(php_stream_wrapper *wrapper,
    char *filename, char *mode, int options,
    char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) {
    
    // filename 格式: "memory://data_id" 或直接內容
    // 此處簡化:從 context 或全域取得預載資料
    
    php_stream *stream = php_stream_alloc(&php_memory_ops, NULL, 0, mode);
    // 設定 abstract...
    return stream;
}

// 4. 註冊
PHP_MINIT_FUNCTION(memory_wrapper) {
    php_stream_wrapper wrapper;
    wrapper.wops = &php_memory_wrapper_ops;
    wrapper.is_url = 0;
    wrapper.flags = 0;
    return php_register_url_stream_wrapper("memory", &wrapper TSRMLS_CC);
}

進階:流過濾器

流過濾器 (php_stream_filter) 可在讀寫管道中插入轉換邏輯 (Base64、旋轉加密、壓縮、字元編碼轉換),詳見第 16 章。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved