(PHP 4 >= 4.3.0, PHP 5, PHP 7)
stream_register_wrapper — 注册一个用 PHP 类实现的 URL 封装协议
$protocol
, string $classname
)stream_register_wrapper() 允许用户实现自定义的协议处理器和流,用于所有其它的文件系统函数中(例如 fopen(),fread() 等)。
要实现一个封装协议,需要按照如下定义声明一个包含有一些函数的类。当有人对你的流使用
fopen 时,PHP 将创建一个 classname
的实例并调用该实例的方法。必须严格按照如下的描述实现方法 - 否则将导致不明确的行为。
如果 protocol
已经有了处理协议,则 stream_register_wrapper()
将返回 FALSE
。
$path
, string $mode
, int $options
, string $opened_path
)
当你的流对象被创建之后立即会调用此方法。path
指定了传入 fopen() 以及此对象需要取回的 URL。可以用
parse_url() 来将此 URL 分割成几部分。
mode
用来打开文件的模式,和
fopen() 中的一样。你有责任检查
mode
对于所请求的
path
是否合法。
options
保存了通过流 API
设定的附加标志。可以保存以下一个值或者用 OR 合并的多个值。
标志 | 说明 |
---|---|
STREAM_USE_PATH | 如果 path 是相对路径,则用
include_path 搜索资源。
|
STREAM_REPORT_ERRORS | 如果设定了本标志,你有责任在打开流时用 trigger_error() 来唤起错误。如果没有设定这个标志,那么你不需要唤起任何错误。 |
如果成功打开了 path
,并且在 options
中设定了 STREAM_USE_PATH,你需要将 opened_path
设定为实际被打开的文件/资源的完整路径。
如果成功打开了所请求的资源,应该返回
TRUE
,否则返回 FALSE
。
本方法在流关闭时被调用,使用 fclose()。必须释放被流锁定或分配的任何资源。
$count
)
当对流进行 fread() 和 fgets()
操作时本方法被调用。必须从当前读写位置以字符串返回最多
count
字节的数据。如果可用数据少于 count
字节,则返回尽可能多的数据。如果没有可供返回的数据,返回 FALSE
或者空字符串。必须用成功读取的字节数去更新流的读写位置。
$data
)
当对流进行 fwrite()
操作时本方法被调用。必须将 data
储存到你的流使用的底层存储空间去。如果没有足够的空间了,则试着保存尽可能多的字节。应该返回成功被保存入流的字节数,或者没有保存时返回
0。必须用成功写入的字节数去更新流的读写位置。
当对流进行 feof()
操作时本方法被调用。如果读写位置到了流的尽头或者没有更多数据可读时返回
TRUE
,否则返回 FALSE
。
当对流进行 ftell() 操作时本方法被调用。应该返回流的当前读写位置。
$offset
, int $whence
)
当对流进行 fseek()
操作时本方法被调用。应该根据 offset
和
whence
来更新流的读写位置。这些参数的更多信息见
fseek()。如果位置成功更新了则返回 TRUE
,否则返回 FALSE
。
当对流进行 fflush()
操作时本方法被调用。如果你在流中缓存了数据还没有写入底层存储空间时,那现在应该做了。如果缓存数据被成功保存(或没有数据可供保存)时返回
TRUE
,当数据无法被保存时返回 FALSE
。
下面的例子实现了一个 var:// 协议处理器,可以允许使用标准的文件系统流函数来对指定的全局变量进行读写操作,例如 fread()。var:// 协议的实现如下,给出 url "var://foo" 将可以读写 $GLOBALS["foo"]。
Example #1 读写全局变量的流
class VariableStream {
var $position;
var $varname;
function stream_open($path, $mode, $options, &$opened_path)
{
$url = parse_url($path);
$this->varname = $url["host"];
$this->position = 0;
return true;
}
function stream_read($count)
{
$ret = substr($GLOBALS[$this->varname], $this->position, $count);
$this->position += strlen($ret);
return $ret;
}
function stream_write($data)
{
$left = substr($GLOBALS[$this->varname], 0, $this->position);
$right = substr($GLOBALS[$this->varname], $this->position + strlen($data));
$GLOBALS[$this->varname] = $left . $data . $right;
$this->position += strlen($data);
return strlen($data);
}
function stream_tell()
{
return $this->position;
}
function stream_eof()
{
return $this->position >= strlen($GLOBALS[$this->varname]);
}
function stream_seek($offset, $whence)
{
switch($whence) {
case SEEK_SET:
if ($offset < strlen($GLOBALS[$this->varname]) && $offset >= 0) {
$this->position = $offset;
return true;
} else {
return false;
}
break;
case SEEK_CUR:
if ($offset >= 0) {
$this->position += $offset;
return true;
} else {
return false;
}
break;
case SEEK_END:
if (strlen($GLOBALS[$this->varname]) + $offset >= 0) {
$this->position = strlen($GLOBALS[$this->varname]) + $offset;
return true;
} else {
return false;
}
break;
default:
return false;
}
}
}
stream_register_wrapper("var", "VariableStream")
or die("Failed to register protocol");
$myvar = "";
$fp = fopen("var://myvar", "r+");
fwrite($fp, "line1\n");
fwrite($fp, "line2\n");
fwrite($fp, "line3\n");
rewind($fp);
while(!feof($fp)) {
echo fgets($fp)
}
fclose($fp);
var_dump($myvar);