PHP源码分析-流的实现之标准输入
前一篇文章写了如何去查找留的通用实现往后章针对一个具体的流来探索下php是如何实现的.先从简单的开始------标准输入流的封装-php://stdin
首先接上一章,获取到’php://'流的实现
php_register_url_stream_wrapper("php", &php_stream_php_wrapper);
然后继续追踪代码查找php_stream_php_wrapper的赋值,此处的php_stream_php_wrapper可以认为是php流工厂的一个实例.
PHPAPI const php_stream_wrapper php_stream_php_wrapper = {
&php_stdio_wops,
NULL,
0, /* is_url */
};
不用看php_stream_wrapper 结构体只看内容 NULL和0忽略,那么相关的实现就是在php_stdio_wops中.
static const php_stream_wrapper_ops php_stdio_wops = {
php_stream_url_wrap_php,
NULL, /* close */
NULL, /* fstat */
NULL, /* stat */
NULL, /* opendir */
"PHP",
NULL, /* unlink */
NULL, /* rename */
NULL, /* mkdir */
NULL, /* rmdir */
NULL
};
同理只关心php_stream_url_wrap_php的实现即可.
经定位
php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const char *path, const char *mode, int options,
zend_string **opened_path, php_stream_context *context STREAMS_DC) /* {{{ */
{
//一些准备工作
if (!strncasecmp(path, "php://", 6)) {//check-1
path += 6;
}
//另一些代码
if (!strcasecmp(path, "stdin")) {//check-2
if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) {
if (options & REPORT_ERRORS) {
php_error_docref(NULL, E_WARNING, "URL file-access is disabled in the server configuration");
}
return NULL;
}
if (!strcmp(sapi_module.name, "cli")) {
static int cli_in = 0;
fd = STDIN_FILENO;
if (cli_in) {
fd = dup(fd);
} else {
cli_in = 1;
file = stdin;
}
} else {
fd = dup(STDIN_FILENO);
}
#ifdef PHP_WIN32
pipe_requested = 1;
#endif
}
//省略其他代码
}
check-1 :path是个指针(const的用暂时忽略,不是本章重点).首先匹配到php://则向后移动6位指针.然后到达check-2
check-2:如果匹配到stdin则进行处理,关键点在于dup()函数和STDIN_FILENO常量.
STDIN_FILENO是个宏定义
#define STDIN_FILENO 0
dup()则是个Linux的系统函数.
Linux的系统在启动的时候会默认打开三个流符其中是
标准输入流 代号 0
标准输出流 代号 1
标准错误流 代号 2
流在Linux也可认为是文件描述符,dup的作用就是复制一个文件描述符,注意此处是复制,不是返回指向相应文件描述符的指针(至于为什么不用句柄的概念,因为windows里也有相关的概念必免混淆还是使用写一些便于理解的术语.仁者见仁智者见智).
***In Unix-like operating systems, dup (short for “duplicate”) and dup2 system calls create a copy of a given file descriptor. This new descriptor actually does not behave like a copy, but like an alias of the old one.***-----来自维基百科
通过dup(),php便完成了对标准流的处理,这里只介绍了标注输入流,(这里在php的源码中至少在笔者使用的源码是有BUG的,但是不影响使用).其他如标准错误流和输出流大家可自行查看源码.
在php手册中有如下描述
php://stdin, php://stdout 和 php://stderr
php://stdin、php://stdout 和 php://stderr 允许直接访问 PHP 进程相应的输入或者输出流。 数据流引用了复制的文件描述符,所以如果你打开 php://stdin 并在之后关了它, 仅是关闭了复制品,真正被引用的 STDIN 并不受影响。 注意 PHP 在这方面的行为有很多 BUG 直到 PHP 5.2.1。 推荐你简单使用常量 STDIN、 STDOUT 和 STDERR 来代替手工打开这些封装器。
此处是标准流的两种打开方法.再往下
php://fd
php://fd 允许直接访问指定的文件描述符。 例如 php://fd/3 引用了文件描述符 3
根据这两段php的手册描述我想大家也能很容易的想到标准流在PHP种的第三种打开方法.
(^▽^)
如有错误欢迎大家指正