HproseWriter.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. <?php
  2. /**********************************************************\
  3. | |
  4. | hprose |
  5. | |
  6. | Official WebSite: http://www.hprose.com/ |
  7. | http://www.hprose.net/ |
  8. | http://www.hprose.org/ |
  9. | |
  10. \**********************************************************/
  11. /**********************************************************\
  12. * *
  13. * HproseWriter.php *
  14. * *
  15. * hprose writer library for php5. *
  16. * *
  17. * LastModified: Nov 13, 2013 *
  18. * Author: Ma Bingyao <andot@hprfc.com> *
  19. * *
  20. \**********************************************************/
  21. require_once('HproseCommon.php');
  22. require_once('HproseTags.php');
  23. require_once('HproseClassManager.php');
  24. class HproseSimpleWriter {
  25. public $stream;
  26. private $classref;
  27. private $fieldsref;
  28. function __construct(&$stream) {
  29. $this->stream = &$stream;
  30. $this->classref = array();
  31. $this->fieldsref = array();
  32. }
  33. public function serialize(&$var) {
  34. if ((!isset($var)) || ($var === NULL)) {
  35. $this->writeNull();
  36. }
  37. elseif (is_scalar($var)) {
  38. if (is_int($var)) {
  39. $this->writeInteger($var);
  40. }
  41. elseif (is_bool($var)) {
  42. $this->writeBoolean($var);
  43. }
  44. elseif (is_float($var)) {
  45. $this->writeDouble($var);
  46. }
  47. elseif (is_string($var)) {
  48. if ($var === '') {
  49. $this->writeEmpty();
  50. }
  51. elseif ((strlen($var) < 4) && is_utf8($var) && (ustrlen($var) == 1)) {
  52. $this->writeUTF8Char($var);
  53. }
  54. elseif (is_utf8($var)) {
  55. $this->writeString($var, true);
  56. }
  57. else {
  58. $this->writeBytes($var, true);
  59. }
  60. }
  61. }
  62. elseif (is_array($var)) {
  63. if (is_list($var)) {
  64. $this->writeList($var, true);
  65. }
  66. else {
  67. $this->writeMap($var, true);
  68. }
  69. }
  70. elseif (is_object($var)) {
  71. if ($var instanceof stdClass) {
  72. $this->writeStdObject($var, true);
  73. }
  74. elseif (($var instanceof HproseDate) || ($var instanceof HproseDateTime)) {
  75. $this->writeDate($var, true);
  76. }
  77. elseif ($var instanceof HproseTime) {
  78. $this->writeTime($var, true);
  79. }
  80. else {
  81. $this->writeObject($var, true);
  82. }
  83. }
  84. else {
  85. throw new HproseException('Not support to serialize this data');
  86. }
  87. }
  88. public function writeInteger($integer) {
  89. if ($integer >= 0 && $integer <= 9) {
  90. $this->stream->write((string)$integer);
  91. }
  92. else {
  93. $this->stream->write(HproseTags::TagInteger . $integer . HproseTags::TagSemicolon);
  94. }
  95. }
  96. public function writeLong($long) {
  97. if ($long >= '0' && $long <= '9') {
  98. $this->stream->write($long);
  99. }
  100. else {
  101. $this->stream->write(HproseTags::TagLong . $long . HproseTags::TagSemicolon);
  102. }
  103. }
  104. public function writeDouble($double) {
  105. if (is_nan($double)) {
  106. $this->writeNaN();
  107. }
  108. elseif (is_infinite($double)) {
  109. $this->writeInfinity($double > 0);
  110. }
  111. else {
  112. $this->stream->write(HproseTags::TagDouble . $double . HproseTags::TagSemicolon);
  113. }
  114. }
  115. public function writeNaN() {
  116. $this->stream->write(HproseTags::TagNaN);
  117. }
  118. public function writeInfinity($positive = true) {
  119. $this->stream->write(HproseTags::TagInfinity . ($positive ? HproseTags::TagPos : HproseTags::TagNeg));
  120. }
  121. public function writeNull() {
  122. $this->stream->write(HproseTags::TagNull);
  123. }
  124. public function writeEmpty() {
  125. $this->stream->write(HproseTags::TagEmpty);
  126. }
  127. public function writeBoolean($bool) {
  128. $this->stream->write($bool ? HproseTags::TagTrue : HproseTags::TagFalse);
  129. }
  130. public function writeDate($date, $checkRef = false) {
  131. if ($date->utc) {
  132. $this->stream->write(HproseTags::TagDate . $date->toString(false));
  133. }
  134. else {
  135. $this->stream->write(HproseTags::TagDate . $date->toString(false) . HproseTags::TagSemicolon);
  136. }
  137. }
  138. public function writeTime($time, $checkRef = false) {
  139. if ($time->utc) {
  140. $this->stream->write(HproseTags::TagTime . $time->toString(false));
  141. }
  142. else {
  143. $this->stream->write(HproseTags::TagTime . $time->toString(false) . HproseTags::TagSemicolon);
  144. }
  145. }
  146. public function writeBytes($bytes, $checkRef = false) {
  147. $len = strlen($bytes);
  148. $this->stream->write(HproseTags::TagBytes);
  149. if ($len > 0) $this->stream->write((string)$len);
  150. $this->stream->write(HproseTags::TagQuote . $bytes . HproseTags::TagQuote);
  151. }
  152. public function writeUTF8Char($char) {
  153. $this->stream->write(HproseTags::TagUTF8Char . $char);
  154. }
  155. public function writeString($str, $checkRef = false) {
  156. $len = ustrlen($str);
  157. $this->stream->write(HproseTags::TagString);
  158. if ($len > 0) $this->stream->write((string)$len);
  159. $this->stream->write(HproseTags::TagQuote . $str . HproseTags::TagQuote);
  160. }
  161. public function writeList(&$list, $checkRef = false) {
  162. $count = count($list);
  163. $this->stream->write(HproseTags::TagList);
  164. if ($count > 0) $this->stream->write((string)$count);
  165. $this->stream->write(HproseTags::TagOpenbrace);
  166. for ($i = 0; $i < $count; ++$i) {
  167. $this->serialize($list[$i]);
  168. }
  169. $this->stream->write(HproseTags::TagClosebrace);
  170. }
  171. public function writeMap(&$map, $checkRef = false) {
  172. $count = count($map);
  173. $this->stream->write(HproseTags::TagMap);
  174. if ($count > 0) $this->stream->write((string)$count);
  175. $this->stream->write(HproseTags::TagOpenbrace);
  176. foreach ($map as $key => &$value) {
  177. $this->serialize($key);
  178. $this->serialize($value);
  179. }
  180. $this->stream->write(HproseTags::TagClosebrace);
  181. }
  182. public function writeStdObject($obj, $checkRef = false) {
  183. $map = (array)$obj;
  184. self::writeMap($map);
  185. }
  186. protected function writeObjectBegin($obj) {
  187. $class = get_class($obj);
  188. $alias = HproseClassManager::getClassAlias($class);
  189. $fields = array_keys((array)$obj);
  190. if (array_key_exists($alias, $this->classref)) {
  191. $index = $this->classref[$alias];
  192. }
  193. else {
  194. $index = $this->writeClass($alias, $fields);
  195. }
  196. return $index;
  197. }
  198. protected function writeObjectEnd($obj, $index) {
  199. $fields = $this->fieldsref[$index];
  200. $count = count($fields);
  201. $this->stream->write(HproseTags::TagObject . $index . HproseTags::TagOpenbrace);
  202. $array = (array)$obj;
  203. for ($i = 0; $i < $count; ++$i) {
  204. $this->serialize($array[$fields[$i]]);
  205. }
  206. $this->stream->write(HproseTags::TagClosebrace);
  207. }
  208. public function writeObject($obj, $checkRef = false) {
  209. $this->writeObjectEnd($obj, $this->writeObjectBegin($obj));
  210. }
  211. protected function writeClass($alias, $fields) {
  212. $len = ustrlen($alias);
  213. $this->stream->write(HproseTags::TagClass . $len .
  214. HproseTags::TagQuote . $alias . HproseTags::TagQuote);
  215. $count = count($fields);
  216. if ($count > 0) $this->stream->write((string)$count);
  217. $this->stream->write(HproseTags::TagOpenbrace);
  218. for ($i = 0; $i < $count; ++$i) {
  219. $field = $fields[$i];
  220. if ($field{0} === "\0") {
  221. $field = substr($field, strpos($field, "\0", 1) + 1);
  222. }
  223. $this->writeString($field);
  224. }
  225. $this->stream->write(HproseTags::TagClosebrace);
  226. $index = count($this->fieldsref);
  227. $this->classref[$alias] = $index;
  228. $this->fieldsref[$index] = $fields;
  229. return $index;
  230. }
  231. public function reset() {
  232. $this->classref = array();
  233. $this->fieldsref = array();
  234. }
  235. }
  236. class HproseWriter extends HproseSimpleWriter {
  237. private $ref;
  238. private $arrayref;
  239. function __construct(&$stream) {
  240. parent::__construct($stream);
  241. $this->ref = array();
  242. $this->arrayref = array();
  243. }
  244. private function writeRef(&$obj, $checkRef, $writeBegin, $writeEnd) {
  245. if (is_string($obj)) {
  246. $key = 's_' . $obj;
  247. }
  248. elseif (is_array($obj)) {
  249. if (($i = array_ref_search($obj, $this->arrayref)) === false) {
  250. $i = count($this->arrayref);
  251. $this->arrayref[$i] = &$obj;
  252. }
  253. $key = 'a_' . $i;
  254. }
  255. else {
  256. $key = 'o_' . spl_object_hash($obj);
  257. }
  258. if ($checkRef && array_key_exists($key, $this->ref)) {
  259. $this->stream->write(HproseTags::TagRef . $this->ref[$key] . HproseTags::TagSemicolon);
  260. }
  261. else {
  262. $result = $writeBegin ? call_user_func_array($writeBegin, array(&$obj)) : false;
  263. $index = count($this->ref);
  264. $this->ref[$key] = $index;
  265. call_user_func_array($writeEnd, array(&$obj, $result));
  266. }
  267. }
  268. public function writeDate($date, $checkRef = false) {
  269. $this->writeRef($date, $checkRef, NULL, array(&$this, 'parent::writeDate'));
  270. }
  271. public function writeTime($time, $checkRef = false) {
  272. $this->writeRef($time, $checkRef, NULL, array(&$this, 'parent::writeTime'));
  273. }
  274. public function writeBytes($bytes, $checkRef = false) {
  275. $this->writeRef($bytes, $checkRef, NULL, array(&$this, 'parent::writeBytes'));
  276. }
  277. public function writeString($str, $checkRef = false) {
  278. $this->writeRef($str, $checkRef, NULL, array(&$this, 'parent::writeString'));
  279. }
  280. public function writeList(&$list, $checkRef = false) {
  281. $this->writeRef($list, $checkRef, NULL, array(&$this, 'parent::writeList'));
  282. }
  283. public function writeMap(&$map, $checkRef = false) {
  284. $this->writeRef($map, $checkRef, NULL, array(&$this, 'parent::writeMap'));
  285. }
  286. public function writeStdObject($obj, $checkRef = false) {
  287. $this->writeRef($obj, $checkRef, NULL, array(&$this, 'parent::writeStdObject'));
  288. }
  289. public function writeObject($obj, $checkRef = false) {
  290. $this->writeRef($obj, $checkRef, array(&$this, 'writeObjectBegin'), array(&$this, 'writeObjectEnd'));
  291. }
  292. public function reset() {
  293. parent::reset();
  294. $this->ref = array();
  295. $this->arrayref = array();
  296. }
  297. }
  298. ?>