为什么会变成数组
是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、.....
有兴趣的同学自行研究吧?