TException.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  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\Exception;
  23. use Thrift\Type\TType;
  24. use Thrift\Base\TBase;
  25. /**
  26. * NOTE(mcslee): This currently contains a ton of duplicated code from TBase
  27. * because we need to save CPU cycles and this is not yet in an extension.
  28. * Ideally we'd multiply-inherit TException from both Exception and Base, but
  29. * that's not possible in PHP and there are no modules either, so for now we
  30. * apologetically take a trip to HackTown.
  31. *
  32. * Can be called with standard Exception constructor (message, code) or with
  33. * Thrift Base object constructor (spec, vals).
  34. *
  35. * @param mixed $p1 Message (string) or type-spec (array)
  36. * @param mixed $p2 Code (integer) or values (array)
  37. */
  38. class TException extends \Exception
  39. {
  40. public function __construct($p1=null, $p2=0)
  41. {
  42. if (is_array($p1) && is_array($p2)) {
  43. $spec = $p1;
  44. $vals = $p2;
  45. foreach ($spec as $fid => $fspec) {
  46. $var = $fspec['var'];
  47. if (isset($vals[$var])) {
  48. $this->$var = $vals[$var];
  49. }
  50. }
  51. } else {
  52. parent::__construct($p1, $p2);
  53. }
  54. }
  55. static $tmethod = array(TType::BOOL => 'Bool',
  56. TType::BYTE => 'Byte',
  57. TType::I16 => 'I16',
  58. TType::I32 => 'I32',
  59. TType::I64 => 'I64',
  60. TType::DOUBLE => 'Double',
  61. TType::STRING => 'String');
  62. private function _readMap(&$var, $spec, $input)
  63. {
  64. $xfer = 0;
  65. $ktype = $spec['ktype'];
  66. $vtype = $spec['vtype'];
  67. $kread = $vread = null;
  68. if (isset(TBase::$tmethod[$ktype])) {
  69. $kread = 'read'.TBase::$tmethod[$ktype];
  70. } else {
  71. $kspec = $spec['key'];
  72. }
  73. if (isset(TBase::$tmethod[$vtype])) {
  74. $vread = 'read'.TBase::$tmethod[$vtype];
  75. } else {
  76. $vspec = $spec['val'];
  77. }
  78. $var = array();
  79. $_ktype = $_vtype = $size = 0;
  80. $xfer += $input->readMapBegin($_ktype, $_vtype, $size);
  81. for ($i = 0; $i < $size; ++$i) {
  82. $key = $val = null;
  83. if ($kread !== null) {
  84. $xfer += $input->$kread($key);
  85. } else {
  86. switch ($ktype) {
  87. case TType::STRUCT:
  88. $class = $kspec['class'];
  89. $key = new $class();
  90. $xfer += $key->read($input);
  91. break;
  92. case TType::MAP:
  93. $xfer += $this->_readMap($key, $kspec, $input);
  94. break;
  95. case TType::LST:
  96. $xfer += $this->_readList($key, $kspec, $input, false);
  97. break;
  98. case TType::SET:
  99. $xfer += $this->_readList($key, $kspec, $input, true);
  100. break;
  101. }
  102. }
  103. if ($vread !== null) {
  104. $xfer += $input->$vread($val);
  105. } else {
  106. switch ($vtype) {
  107. case TType::STRUCT:
  108. $class = $vspec['class'];
  109. $val = new $class();
  110. $xfer += $val->read($input);
  111. break;
  112. case TType::MAP:
  113. $xfer += $this->_readMap($val, $vspec, $input);
  114. break;
  115. case TType::LST:
  116. $xfer += $this->_readList($val, $vspec, $input, false);
  117. break;
  118. case TType::SET:
  119. $xfer += $this->_readList($val, $vspec, $input, true);
  120. break;
  121. }
  122. }
  123. $var[$key] = $val;
  124. }
  125. $xfer += $input->readMapEnd();
  126. return $xfer;
  127. }
  128. private function _readList(&$var, $spec, $input, $set=false)
  129. {
  130. $xfer = 0;
  131. $etype = $spec['etype'];
  132. $eread = $vread = null;
  133. if (isset(TBase::$tmethod[$etype])) {
  134. $eread = 'read'.TBase::$tmethod[$etype];
  135. } else {
  136. $espec = $spec['elem'];
  137. }
  138. $var = array();
  139. $_etype = $size = 0;
  140. if ($set) {
  141. $xfer += $input->readSetBegin($_etype, $size);
  142. } else {
  143. $xfer += $input->readListBegin($_etype, $size);
  144. }
  145. for ($i = 0; $i < $size; ++$i) {
  146. $elem = null;
  147. if ($eread !== null) {
  148. $xfer += $input->$eread($elem);
  149. } else {
  150. $espec = $spec['elem'];
  151. switch ($etype) {
  152. case TType::STRUCT:
  153. $class = $espec['class'];
  154. $elem = new $class();
  155. $xfer += $elem->read($input);
  156. break;
  157. case TType::MAP:
  158. $xfer += $this->_readMap($elem, $espec, $input);
  159. break;
  160. case TType::LST:
  161. $xfer += $this->_readList($elem, $espec, $input, false);
  162. break;
  163. case TType::SET:
  164. $xfer += $this->_readList($elem, $espec, $input, true);
  165. break;
  166. }
  167. }
  168. if ($set) {
  169. $var[$elem] = true;
  170. } else {
  171. $var []= $elem;
  172. }
  173. }
  174. if ($set) {
  175. $xfer += $input->readSetEnd();
  176. } else {
  177. $xfer += $input->readListEnd();
  178. }
  179. return $xfer;
  180. }
  181. protected function _read($class, $spec, $input)
  182. {
  183. $xfer = 0;
  184. $fname = null;
  185. $ftype = 0;
  186. $fid = 0;
  187. $xfer += $input->readStructBegin($fname);
  188. while (true) {
  189. $xfer += $input->readFieldBegin($fname, $ftype, $fid);
  190. if ($ftype == TType::STOP) {
  191. break;
  192. }
  193. if (isset($spec[$fid])) {
  194. $fspec = $spec[$fid];
  195. $var = $fspec['var'];
  196. if ($ftype == $fspec['type']) {
  197. $xfer = 0;
  198. if (isset(TBase::$tmethod[$ftype])) {
  199. $func = 'read'.TBase::$tmethod[$ftype];
  200. $xfer += $input->$func($this->$var);
  201. } else {
  202. switch ($ftype) {
  203. case TType::STRUCT:
  204. $class = $fspec['class'];
  205. $this->$var = new $class();
  206. $xfer += $this->$var->read($input);
  207. break;
  208. case TType::MAP:
  209. $xfer += $this->_readMap($this->$var, $fspec, $input);
  210. break;
  211. case TType::LST:
  212. $xfer += $this->_readList($this->$var, $fspec, $input, false);
  213. break;
  214. case TType::SET:
  215. $xfer += $this->_readList($this->$var, $fspec, $input, true);
  216. break;
  217. }
  218. }
  219. } else {
  220. $xfer += $input->skip($ftype);
  221. }
  222. } else {
  223. $xfer += $input->skip($ftype);
  224. }
  225. $xfer += $input->readFieldEnd();
  226. }
  227. $xfer += $input->readStructEnd();
  228. return $xfer;
  229. }
  230. private function _writeMap($var, $spec, $output)
  231. {
  232. $xfer = 0;
  233. $ktype = $spec['ktype'];
  234. $vtype = $spec['vtype'];
  235. $kwrite = $vwrite = null;
  236. if (isset(TBase::$tmethod[$ktype])) {
  237. $kwrite = 'write'.TBase::$tmethod[$ktype];
  238. } else {
  239. $kspec = $spec['key'];
  240. }
  241. if (isset(TBase::$tmethod[$vtype])) {
  242. $vwrite = 'write'.TBase::$tmethod[$vtype];
  243. } else {
  244. $vspec = $spec['val'];
  245. }
  246. $xfer += $output->writeMapBegin($ktype, $vtype, count($var));
  247. foreach ($var as $key => $val) {
  248. if (isset($kwrite)) {
  249. $xfer += $output->$kwrite($key);
  250. } else {
  251. switch ($ktype) {
  252. case TType::STRUCT:
  253. $xfer += $key->write($output);
  254. break;
  255. case TType::MAP:
  256. $xfer += $this->_writeMap($key, $kspec, $output);
  257. break;
  258. case TType::LST:
  259. $xfer += $this->_writeList($key, $kspec, $output, false);
  260. break;
  261. case TType::SET:
  262. $xfer += $this->_writeList($key, $kspec, $output, true);
  263. break;
  264. }
  265. }
  266. if (isset($vwrite)) {
  267. $xfer += $output->$vwrite($val);
  268. } else {
  269. switch ($vtype) {
  270. case TType::STRUCT:
  271. $xfer += $val->write($output);
  272. break;
  273. case TType::MAP:
  274. $xfer += $this->_writeMap($val, $vspec, $output);
  275. break;
  276. case TType::LST:
  277. $xfer += $this->_writeList($val, $vspec, $output, false);
  278. break;
  279. case TType::SET:
  280. $xfer += $this->_writeList($val, $vspec, $output, true);
  281. break;
  282. }
  283. }
  284. }
  285. $xfer += $output->writeMapEnd();
  286. return $xfer;
  287. }
  288. private function _writeList($var, $spec, $output, $set=false)
  289. {
  290. $xfer = 0;
  291. $etype = $spec['etype'];
  292. $ewrite = null;
  293. if (isset(TBase::$tmethod[$etype])) {
  294. $ewrite = 'write'.TBase::$tmethod[$etype];
  295. } else {
  296. $espec = $spec['elem'];
  297. }
  298. if ($set) {
  299. $xfer += $output->writeSetBegin($etype, count($var));
  300. } else {
  301. $xfer += $output->writeListBegin($etype, count($var));
  302. }
  303. foreach ($var as $key => $val) {
  304. $elem = $set ? $key : $val;
  305. if (isset($ewrite)) {
  306. $xfer += $output->$ewrite($elem);
  307. } else {
  308. switch ($etype) {
  309. case TType::STRUCT:
  310. $xfer += $elem->write($output);
  311. break;
  312. case TType::MAP:
  313. $xfer += $this->_writeMap($elem, $espec, $output);
  314. break;
  315. case TType::LST:
  316. $xfer += $this->_writeList($elem, $espec, $output, false);
  317. break;
  318. case TType::SET:
  319. $xfer += $this->_writeList($elem, $espec, $output, true);
  320. break;
  321. }
  322. }
  323. }
  324. if ($set) {
  325. $xfer += $output->writeSetEnd();
  326. } else {
  327. $xfer += $output->writeListEnd();
  328. }
  329. return $xfer;
  330. }
  331. protected function _write($class, $spec, $output)
  332. {
  333. $xfer = 0;
  334. $xfer += $output->writeStructBegin($class);
  335. foreach ($spec as $fid => $fspec) {
  336. $var = $fspec['var'];
  337. if ($this->$var !== null) {
  338. $ftype = $fspec['type'];
  339. $xfer += $output->writeFieldBegin($var, $ftype, $fid);
  340. if (isset(TBase::$tmethod[$ftype])) {
  341. $func = 'write'.TBase::$tmethod[$ftype];
  342. $xfer += $output->$func($this->$var);
  343. } else {
  344. switch ($ftype) {
  345. case TType::STRUCT:
  346. $xfer += $this->$var->write($output);
  347. break;
  348. case TType::MAP:
  349. $xfer += $this->_writeMap($this->$var, $fspec, $output);
  350. break;
  351. case TType::LST:
  352. $xfer += $this->_writeList($this->$var, $fspec, $output, false);
  353. break;
  354. case TType::SET:
  355. $xfer += $this->_writeList($this->$var, $fspec, $output, true);
  356. break;
  357. }
  358. }
  359. $xfer += $output->writeFieldEnd();
  360. }
  361. }
  362. $xfer += $output->writeFieldStop();
  363. $xfer += $output->writeStructEnd();
  364. return $xfer;
  365. }
  366. }