TBase.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. <?php
  2. /*
  3. * Licensed to the Apache Software Foundation (ASF) under one
  4. * or more contributor license agreements. See the NOTICE file
  5. * distributed with this work for additional information
  6. * regarding copyright ownership. The ASF licenses this file
  7. * to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance
  9. * with the License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing,
  14. * software distributed under the License is distributed on an
  15. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  16. * KIND, either express or implied. See the License for the
  17. * specific language governing permissions and limitations
  18. * under the License.
  19. *
  20. * @package thrift
  21. */
  22. namespace Thrift\Base;
  23. use Thrift\Type\TType;
  24. /**
  25. * Base class from which other Thrift structs extend. This is so that we can
  26. * cut back on the size of the generated code which is turning out to have a
  27. * nontrivial cost just to load thanks to the wondrously abysmal implementation
  28. * of PHP. Note that code is intentionally duplicated in here to avoid making
  29. * function calls for every field or member of a container..
  30. */
  31. abstract class TBase
  32. {
  33. static $tmethod = array(TType::BOOL => 'Bool',
  34. TType::BYTE => 'Byte',
  35. TType::I16 => 'I16',
  36. TType::I32 => 'I32',
  37. TType::I64 => 'I64',
  38. TType::DOUBLE => 'Double',
  39. TType::STRING => 'String');
  40. abstract public function read($input);
  41. abstract public function write($output);
  42. public function __construct($spec=null, $vals=null)
  43. {
  44. if (is_array($spec) && is_array($vals)) {
  45. foreach ($spec as $fid => $fspec) {
  46. $var = $fspec['var'];
  47. if (isset($vals[$var])) {
  48. $this->$var = $vals[$var];
  49. }
  50. }
  51. }
  52. }
  53. public function __wakeup()
  54. {
  55. $this->__construct(get_object_vars($this));
  56. }
  57. private function _readMap(&$var, $spec, $input)
  58. {
  59. $xfer = 0;
  60. $ktype = $spec['ktype'];
  61. $vtype = $spec['vtype'];
  62. $kread = $vread = null;
  63. if (isset(TBase::$tmethod[$ktype])) {
  64. $kread = 'read'.TBase::$tmethod[$ktype];
  65. } else {
  66. $kspec = $spec['key'];
  67. }
  68. if (isset(TBase::$tmethod[$vtype])) {
  69. $vread = 'read'.TBase::$tmethod[$vtype];
  70. } else {
  71. $vspec = $spec['val'];
  72. }
  73. $var = array();
  74. $_ktype = $_vtype = $size = 0;
  75. $xfer += $input->readMapBegin($_ktype, $_vtype, $size);
  76. for ($i = 0; $i < $size; ++$i) {
  77. $key = $val = null;
  78. if ($kread !== null) {
  79. $xfer += $input->$kread($key);
  80. } else {
  81. switch ($ktype) {
  82. case TType::STRUCT:
  83. $class = $kspec['class'];
  84. $key = new $class();
  85. $xfer += $key->read($input);
  86. break;
  87. case TType::MAP:
  88. $xfer += $this->_readMap($key, $kspec, $input);
  89. break;
  90. case TType::LST:
  91. $xfer += $this->_readList($key, $kspec, $input, false);
  92. break;
  93. case TType::SET:
  94. $xfer += $this->_readList($key, $kspec, $input, true);
  95. break;
  96. }
  97. }
  98. if ($vread !== null) {
  99. $xfer += $input->$vread($val);
  100. } else {
  101. switch ($vtype) {
  102. case TType::STRUCT:
  103. $class = $vspec['class'];
  104. $val = new $class();
  105. $xfer += $val->read($input);
  106. break;
  107. case TType::MAP:
  108. $xfer += $this->_readMap($val, $vspec, $input);
  109. break;
  110. case TType::LST:
  111. $xfer += $this->_readList($val, $vspec, $input, false);
  112. break;
  113. case TType::SET:
  114. $xfer += $this->_readList($val, $vspec, $input, true);
  115. break;
  116. }
  117. }
  118. $var[$key] = $val;
  119. }
  120. $xfer += $input->readMapEnd();
  121. return $xfer;
  122. }
  123. private function _readList(&$var, $spec, $input, $set=false)
  124. {
  125. $xfer = 0;
  126. $etype = $spec['etype'];
  127. $eread = $vread = null;
  128. if (isset(TBase::$tmethod[$etype])) {
  129. $eread = 'read'.TBase::$tmethod[$etype];
  130. } else {
  131. $espec = $spec['elem'];
  132. }
  133. $var = array();
  134. $_etype = $size = 0;
  135. if ($set) {
  136. $xfer += $input->readSetBegin($_etype, $size);
  137. } else {
  138. $xfer += $input->readListBegin($_etype, $size);
  139. }
  140. for ($i = 0; $i < $size; ++$i) {
  141. $elem = null;
  142. if ($eread !== null) {
  143. $xfer += $input->$eread($elem);
  144. } else {
  145. $espec = $spec['elem'];
  146. switch ($etype) {
  147. case TType::STRUCT:
  148. $class = $espec['class'];
  149. $elem = new $class();
  150. $xfer += $elem->read($input);
  151. break;
  152. case TType::MAP:
  153. $xfer += $this->_readMap($elem, $espec, $input);
  154. break;
  155. case TType::LST:
  156. $xfer += $this->_readList($elem, $espec, $input, false);
  157. break;
  158. case TType::SET:
  159. $xfer += $this->_readList($elem, $espec, $input, true);
  160. break;
  161. }
  162. }
  163. if ($set) {
  164. $var[$elem] = true;
  165. } else {
  166. $var []= $elem;
  167. }
  168. }
  169. if ($set) {
  170. $xfer += $input->readSetEnd();
  171. } else {
  172. $xfer += $input->readListEnd();
  173. }
  174. return $xfer;
  175. }
  176. protected function _read($class, $spec, $input)
  177. {
  178. $xfer = 0;
  179. $fname = null;
  180. $ftype = 0;
  181. $fid = 0;
  182. $xfer += $input->readStructBegin($fname);
  183. while (true) {
  184. $xfer += $input->readFieldBegin($fname, $ftype, $fid);
  185. if ($ftype == TType::STOP) {
  186. break;
  187. }
  188. if (isset($spec[$fid])) {
  189. $fspec = $spec[$fid];
  190. $var = $fspec['var'];
  191. if ($ftype == $fspec['type']) {
  192. $xfer = 0;
  193. if (isset(TBase::$tmethod[$ftype])) {
  194. $func = 'read'.TBase::$tmethod[$ftype];
  195. $xfer += $input->$func($this->$var);
  196. } else {
  197. switch ($ftype) {
  198. case TType::STRUCT:
  199. $class = $fspec['class'];
  200. $this->$var = new $class();
  201. $xfer += $this->$var->read($input);
  202. break;
  203. case TType::MAP:
  204. $xfer += $this->_readMap($this->$var, $fspec, $input);
  205. break;
  206. case TType::LST:
  207. $xfer += $this->_readList($this->$var, $fspec, $input, false);
  208. break;
  209. case TType::SET:
  210. $xfer += $this->_readList($this->$var, $fspec, $input, true);
  211. break;
  212. }
  213. }
  214. } else {
  215. $xfer += $input->skip($ftype);
  216. }
  217. } else {
  218. $xfer += $input->skip($ftype);
  219. }
  220. $xfer += $input->readFieldEnd();
  221. }
  222. $xfer += $input->readStructEnd();
  223. return $xfer;
  224. }
  225. private function _writeMap($var, $spec, $output)
  226. {
  227. $xfer = 0;
  228. $ktype = $spec['ktype'];
  229. $vtype = $spec['vtype'];
  230. $kwrite = $vwrite = null;
  231. if (isset(TBase::$tmethod[$ktype])) {
  232. $kwrite = 'write'.TBase::$tmethod[$ktype];
  233. } else {
  234. $kspec = $spec['key'];
  235. }
  236. if (isset(TBase::$tmethod[$vtype])) {
  237. $vwrite = 'write'.TBase::$tmethod[$vtype];
  238. } else {
  239. $vspec = $spec['val'];
  240. }
  241. $xfer += $output->writeMapBegin($ktype, $vtype, count($var));
  242. foreach ($var as $key => $val) {
  243. if (isset($kwrite)) {
  244. $xfer += $output->$kwrite($key);
  245. } else {
  246. switch ($ktype) {
  247. case TType::STRUCT:
  248. $xfer += $key->write($output);
  249. break;
  250. case TType::MAP:
  251. $xfer += $this->_writeMap($key, $kspec, $output);
  252. break;
  253. case TType::LST:
  254. $xfer += $this->_writeList($key, $kspec, $output, false);
  255. break;
  256. case TType::SET:
  257. $xfer += $this->_writeList($key, $kspec, $output, true);
  258. break;
  259. }
  260. }
  261. if (isset($vwrite)) {
  262. $xfer += $output->$vwrite($val);
  263. } else {
  264. switch ($vtype) {
  265. case TType::STRUCT:
  266. $xfer += $val->write($output);
  267. break;
  268. case TType::MAP:
  269. $xfer += $this->_writeMap($val, $vspec, $output);
  270. break;
  271. case TType::LST:
  272. $xfer += $this->_writeList($val, $vspec, $output, false);
  273. break;
  274. case TType::SET:
  275. $xfer += $this->_writeList($val, $vspec, $output, true);
  276. break;
  277. }
  278. }
  279. }
  280. $xfer += $output->writeMapEnd();
  281. return $xfer;
  282. }
  283. private function _writeList($var, $spec, $output, $set=false)
  284. {
  285. $xfer = 0;
  286. $etype = $spec['etype'];
  287. $ewrite = null;
  288. if (isset(TBase::$tmethod[$etype])) {
  289. $ewrite = 'write'.TBase::$tmethod[$etype];
  290. } else {
  291. $espec = $spec['elem'];
  292. }
  293. if ($set) {
  294. $xfer += $output->writeSetBegin($etype, count($var));
  295. } else {
  296. $xfer += $output->writeListBegin($etype, count($var));
  297. }
  298. foreach ($var as $key => $val) {
  299. $elem = $set ? $key : $val;
  300. if (isset($ewrite)) {
  301. $xfer += $output->$ewrite($elem);
  302. } else {
  303. switch ($etype) {
  304. case TType::STRUCT:
  305. $xfer += $elem->write($output);
  306. break;
  307. case TType::MAP:
  308. $xfer += $this->_writeMap($elem, $espec, $output);
  309. break;
  310. case TType::LST:
  311. $xfer += $this->_writeList($elem, $espec, $output, false);
  312. break;
  313. case TType::SET:
  314. $xfer += $this->_writeList($elem, $espec, $output, true);
  315. break;
  316. }
  317. }
  318. }
  319. if ($set) {
  320. $xfer += $output->writeSetEnd();
  321. } else {
  322. $xfer += $output->writeListEnd();
  323. }
  324. return $xfer;
  325. }
  326. protected function _write($class, $spec, $output)
  327. {
  328. $xfer = 0;
  329. $xfer += $output->writeStructBegin($class);
  330. foreach ($spec as $fid => $fspec) {
  331. $var = $fspec['var'];
  332. if ($this->$var !== null) {
  333. $ftype = $fspec['type'];
  334. $xfer += $output->writeFieldBegin($var, $ftype, $fid);
  335. if (isset(TBase::$tmethod[$ftype])) {
  336. $func = 'write'.TBase::$tmethod[$ftype];
  337. $xfer += $output->$func($this->$var);
  338. } else {
  339. switch ($ftype) {
  340. case TType::STRUCT:
  341. $xfer += $this->$var->write($output);
  342. break;
  343. case TType::MAP:
  344. $xfer += $this->_writeMap($this->$var, $fspec, $output);
  345. break;
  346. case TType::LST:
  347. $xfer += $this->_writeList($this->$var, $fspec, $output, false);
  348. break;
  349. case TType::SET:
  350. $xfer += $this->_writeList($this->$var, $fspec, $output, true);
  351. break;
  352. }
  353. }
  354. $xfer += $output->writeFieldEnd();
  355. }
  356. }
  357. $xfer += $output->writeFieldStop();
  358. $xfer += $output->writeStructEnd();
  359. return $xfer;
  360. }
  361. }