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