关于hprose客户端传入集合对象变成数组解析

379 阅读1分钟

为什么会变成数组

是hprose默认帮我们处理做了转换


转换的规则

当你的参数里面带有对象时,hprose会有下面几个判断

vendor/hprose/hprose/src/Hprose/Writer.php:102

elseif (is_object($val)) {
    if ($val instanceof BytesIO) {
        $this->writeBytesIOWithRef($val);
    }
    elseif ($val instanceof DateTime) {
        $this->writeDateTimeWithRef($val);
    }
    elseif ($val instanceof SplObjectStorage) {
        $this->writeMapWithRef($val);
    }
    elseif ($val instanceof Traversable) {
        $this->writeListWithRef($val);
    }
    elseif ($val instanceof stdClass) {
        $this->writeStdClassWithRef($val);
    }
    else {
        $this->writeObjectWithRef($val);
    }
}

我们的的Collection集合对象,属于第四种情况$val instanceof Traversable

这是因为我们的Collection集合类实现了IteratorAggregate接口,而IteratorAggregate又继承了Traversable接口

class Collection implements ArrayAccess, Arrayable, Countable, IteratorAggregate, Jsonable, JsonSerializable


writeListWithRef的实现

vendor/hprose/hprose/src/Hprose/Writer.php:257

public function writeListWithRef(Traversable $list) {
    if (!$this->refer->write($this->stream, $list)) {
        // 直接到这里,调用了这个方法也就默认使用数组去处理
        $this->writeList($list);
    }
}

tips: RealWriterRefer依赖SplObjectStorage实现了引用的存储,这样以来如果重复传输参数可以减少传输字节数

writeList的实现

public function writeList(Traversable $list) {
    $this->refer->set($list);
    $count = count($list);
    $this->stream->write(Tags::TagList);
    if ($count > 0) {
        $this->stream->write((string)$count);
    }
    $this->stream->write(Tags::TagOpenbrace);
    // 这里是迭代取值
    foreach ($list as $e) {
        $this->serialize($e);
    }
    $this->stream->write(Tags::TagClosebrace);
}

最终collect([1, 2, 3])  => 序列化之后变成 a3{123}}


疑问:为什么服务端传过来的Collection,为什么客户端没有变成array

因为客户端的app/LaravelClient.php里面有一层关于数组的处理,默认把数组转换为集合对象


应该怎样正确传对象参数

结合上面判断条件

1、BytesIO 对象

参考:vendor/hprose/hprose/src/Hprose/BytesIO.php

作用:等同于直接传字符串

例: new BytesIO('hello world, 你好,世界') => b28"hello world, 你好,世界"

2、DateTime

作用:传入日期对象

例:new \DateTime() => D20180710T161744.000000;

服务端可解析为对象

DateTime {#2207
    +"date": "2018-07-10 14:45:55.000000"
    +"timezone_type": 3
    +"timezone": "PRC"
}

3、SplObjectStorage

4、.....

有兴趣的同学自行研究吧😄