[英]Using a custom stream wrapper as test stub for PHP's http:// stream wrapper
I'm writing a custom stream wrapper to use as a stub in unit tests for an HTTP client class that uses the built-in http://
stream wrapper. 我正在编写一个自定义流包装器,用作使用内置http://
流包装器的HTTP客户端类的单元测试中的存根。
Specifically, I need control over the value returned in the 'wrapper_data'
key by calls to stream_get_meta_data
on streams created by the custom stream wrapper. 具体来说,我需要通过调用自定义流包装器创建的流上的stream_get_meta_data
来控制'wrapper_data'
键中返回的值。 Unfortunately, the documentation on custom stream wrappers is woeful and the API seems unintuitive. 不幸的是,有关自定义流包装器的文档很糟糕,API似乎不直观。
What method in a custom wrapper controls the the meta wrapper_data
response? 自定义包装器中的哪个方法控制meta wrapper_data
响应?
Using the class at the bottom I've only been able to get the following result when I var_dump(stream_get_meta_data($stream));
使用底部的类我在var_dump(stream_get_meta_data($stream));
时只能得到以下结果var_dump(stream_get_meta_data($stream));
on streams created with the custom wrapper ... 在使用自定义包装器创建的流上...
array(10) {
'wrapper_data' =>
class CustomHttpStreamWrapper#5 (3) {
public $context =>
resource(13) of type (stream-context)
public $position =>
int(0)
public $bodyData =>
string(14) "test body data"
}
...
But I need to coax the wrapper into yielding something like the following on meta data retrieval so I can test the client class's parsing of the data returned by the real http://
stream wrapper ... 但是我需要哄骗包装器在元数据检索上产生类似下面的内容,这样我就可以测试客户端类对真实http://
流包装器返回的数据的解析...
array(10) {
'wrapper_data' => Array(
[0] => HTTP/1.1 200 OK
[1] => Content-Length: 438
)
...
Here's the code I have currently for the custom wrapper: 这是我目前为自定义包装器提供的代码:
class CustomHttpStreamWrapper {
public $context;
public $position = 0;
public $bodyData = 'test body data';
public function stream_open($path, $mode, $options, &$opened_path) {
return true;
}
public function stream_read($count) {
$this->position += strlen($this->bodyData);
if ($this->position > strlen($this->bodyData)) {
return false;
}
return $this->bodyData;
}
public function stream_eof() {
return $this->position >= strlen($this->bodyData);
}
public function stream_stat() {
return array('wrapper_data' => array('test'));
}
public function stream_tell() {
return $this->position;
}
}
stream_get_meta_data
is implemented in ext/standard/streamfunc.c . stream_get_meta_data
在ext / standard / streamfunc.c中实现 。 The relevant part is 相关部分是
if (stream->wrapperdata) {
MAKE_STD_ZVAL(newval);
MAKE_COPY_ZVAL(&stream->wrapperdata, newval);
add_assoc_zval(return_value, "wrapper_data", newval);
}
ie whatever zval stream->wrapperdata holds is "copied" to/referenced by $retval["wrapper_data"]. 即任何zval stream-> wrapperdata hold被$ retval [“wrapper_data”]“复制”/引用。
Your custom wrapper code is "handled" by user_wrapper_opener
in main/streams/userspace.c . 您的自定义包装器代码由main / streams / userspace.c中的 user_wrapper_opener
“处理”。 And there you have 你有
/* set wrapper data to be a reference to our object */
stream->wrapperdata = us->object;
us->object
"is" the instance of your custom wrapper that has been instantiated for the stream. us->object
“is”已为流实例化的自定义包装器的实例。 I haven't found a way to influence stream->wrapperdata
from userspace scripts other than that. 我还没有找到一种方法来影响来自其他用户空间脚本的stream->wrapperdata
。
But you could implement Iterator / IteratorAggregate and/or ArrayAccess if all you need is foreach($metadata['wrapper_data'] ...)
and $metadata['wrapper_data'][$i]
. 但是你可以实现Iterator / IteratorAggregate和/或ArrayAccess,如果你需要的只是foreach($metadata['wrapper_data'] ...)
和$metadata['wrapper_data'][$i]
。
Eg 例如
<?php
function test() {
stream_wrapper_register("mock", "CustomHttpStreamWrapper") or die("Failed to register protocol");
$fp = fopen("mock://myvar", "r+");
$md = stream_get_meta_data($fp);
echo "Iterator / IteratorAggregate\n";
foreach($md['wrapper_data'] as $e) {
echo $e, "\n";
}
echo "\nArrayAccess\n";
echo $md['wrapper_data'][0], "\n";
echo "\nvar_dump\n";
echo var_dump($md['wrapper_data']);
}
class CustomHttpStreamWrapper implements IteratorAggregate, ArrayAccess {
public $context;
public $position = 0;
public $bodyData = 'test body data';
protected $foo = array('HTTP/1.1 200 OK', 'Content-Length: 438', 'foo: bar', 'ham: eggs');
/* IteratorAggregate */
public function getIterator() {
return new ArrayIterator($this->foo);
}
/* ArrayAccess */
public function offsetExists($offset) { return array_key_exists($offset, $this->foo); }
public function offsetGet($offset ) { return $this->foo[$offset]; }
public function offsetSet($offset, $value) { $this->foo[$offset] = $value; }
public function offsetUnset($offset) { unset($this->foo[$offset]); }
/* StreamWrapper */
public function stream_open($path, $mode, $options, &$opened_path) {
return true;
}
public function stream_read($count) {
$this->position += strlen($this->bodyData);
if ($this->position > strlen($this->bodyData)) {
return false;
}
return $this->bodyData;
}
public function stream_eof() {
return $this->position >= strlen($this->bodyData);
}
public function stream_stat() {
return array('wrapper_data' => array('test'));
}
public function stream_tell() {
return $this->position;
}
}
test();
prints 版画
Iterator / IteratorAggregate
HTTP/1.1 200 OK
Content-Length: 438
foo: bar
ham: eggs
ArrayAccess
HTTP/1.1 200 OK
var_dump
object(CustomHttpStreamWrapper)#1 (4) {
["context"]=>
resource(5) of type (stream-context)
["position"]=>
int(0)
["bodyData"]=>
string(14) "test body data"
["foo":protected]=>
array(4) {
[0]=>
string(15) "HTTP/1.1 200 OK"
[1]=>
string(19) "Content-Length: 438"
[2]=>
string(8) "foo: bar"
[3]=>
string(9) "ham: eggs"
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.