7

組み込みのストリームラッパーを使用するHTTPクライアントクラスの単体テストでスタブとして使用するカスタムストリームラッパーを作成していhttp://ます。

具体的には、カスタムストリームラッパーによって作成されたストリームの'wrapper_data'呼び出しによってキーに返される値を制御する必要があります。stream_get_meta_data残念ながら、カスタムストリームラッパーに関するドキュメントはひどく、APIは直感的ではないようです。

カスタムラッパーのどのメソッドがメタwrapper_data応答を制御しますか?

var_dump(stream_get_meta_data($stream));下部のクラスを使用すると、カスタムラッパーで作成されたストリームで次の結果しか得られませんでした...

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"
  }
  ...

http://しかし、実際のストリームラッパーによって返されるデータのクライアントクラスの解析をテストできるように、メタデータの取得で次のようなものを生成するようにラッパーを誘導する必要があります...

array(10) {
  'wrapper_data' => Array(
       [0] => HTTP/1.1 200 OK
       [1] => Content-Length: 438
   )
   ...

カスタムラッパー用に現在持っているコードは次のとおりです。

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;
    }
}
4

1 に答える 1

15

stream_get_meta_dataext/standard/streamfunc.cに実装されています。該当部分は

if (stream->wrapperdata) {
    MAKE_STD_ZVAL(newval);
    MAKE_COPY_ZVAL(&stream->wrapperdata, newval);

    add_assoc_zval(return_value, "wrapper_data", newval);
}

つまり、zval stream->wrapperdata が保持するものはすべて、$retval["wrapper_data"] に「コピー」/参照されます。カスタム ラッパー コードは、main/streams/userspace.c
で 「処理」されます。そして、あなたが持っているuser_wrapper_opener

/* set wrapper data to be a reference to our object */
stream->wrapperdata = us->object;

us->object"is" は、ストリーム用にインスタンス化されたカスタム ラッパーのインスタンスです。stream->wrapperdataそれ以外のユーザー空間スクリプトから影響を与える方法を見つけていません。
ただし、 andだけが必要な場合は、Iterator / IteratorAggregateおよび/またはArrayAccessを実装できます。 例えばforeach($metadata['wrapper_data'] ...)$metadata['wrapper_data'][$i]

<?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();

版画

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"
  }
}
于 2012-07-31T08:15:21.950 に答える