php中流的实现2013-09-09实现流php的流最强力的特性之一是它可以访问众多数据源: 普通文件, 压缩文件, 网络透明通道, 加密网络, 命名管道以及域套接字, 它们对于用户空间以及内部都是统一的API.php流的表象之下对于给定的流实例, 比如文件流和网络流, 它们的不同在于上一章你使用的流创建函数返回的php_stream结构体中的ops成员.
typedef struct _php_stream {...php_stream_ops *ops;...} 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_handleTSRMLS_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 **retTSRMLS_DC);int (*stat)(php_stream *stream, php_stream_statbuf *ssbTSRMLS_DC);int (*set_option)(php_stream *stream, int option,int value,void *ptrparam TSRMLS_DC);} php_stream_ops;当流访问函数比如php_stream_read()被调用时, 流包装层实际上解析调用了stream->ops中对应的函数, 这样实际调用的就是当前流类型特有的read实现. 比如, 普通文件的流ops结构体中的read函数实现如下(实际的该实现比下面的示例复杂一点):
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);}而compress.zlib流使用的ops结构体中则read则指向的是如下的函数:
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);}这里第一点需要注意的是ops结构体指向的函数指针常常是对数据源真正的读取函数的一个瘦代理. 在上面两个例子中, 标准I/O流使用posix的read()函数, 而zlib流使用的是libz的gzread()函数.你可能还注意到了, 这里使用了stream->abstract元素. 这是流实现的一个便利指针, 它可以被用于获取各种相关的捆绑信息. 在上面的例子中, 指向自定义结构体的指针, 用于存储底层read函数要使用的文件描述符.还有一件你可能注意到的事情是php_stream_ops结构体中的每个函数都期望一个已有的流实例, 但是怎样得到实例呢? abstract成员是怎样设置的以及什么时候流指示使用哪个ops结构体? 答案就在你在上一章使用过的第一个打开流的函数(php_stream_open_wrapper())中.当这个函数被调用时, php的流包装层尝试基于传递的URL中的scheme://部分确定请求的是什么协议. 这样它就可以在已注册的php包装器中查找对应的php_stream_wrapper项. 每个php_stream_wrapper结构体都可以取到自己的ops元素, 它指向一个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 *contextSTREAMS_DC TSRMLS_DC);int (*stream_closer)(php_stream_wrapper *wrapper,php_stream *stream TSRMLS_DC);int (*stream_stat)(php_stream_wrapper *wrapper,php_stream *stream,php_stream_statbuf *ssbTSRMLS_DC);int (*url_stat)(php_stream_wrapper *wrapper,char *url, int flags,php_stream_statbuf *ssb,php_stream_context *contextTSRMLS_DC);php_stream *(*dir_opener)(php_stream_wrapper *wrapper,char *filename, char *mode,int options, char **opened_path,php_stream_context *contextSTREAMS_DC TSRMLS_DC);const char *label;int (*unlink)(php_stream_wrapper *wrapper, char *url,int options,php_stream_context *contextTSRMLS_DC);int (*rename)(php_stream_wrapper *wrapper,char *url_from, char *url_to,int options,php_stream_context *contextTSRMLS_DC);int (*stream_mkdir)(php_stream_wrapper *wrapper,char *url, int mode, int options,php_stream_context *contextTSRMLS_DC);int (*stream_rmdir)(php_stream_wrapper *wrapper, char *url,int options,php_stream_context *contextTSRMLS_DC);} php_stream_wrapper_ops;