4 * Copyright (c) 2006- Facebook
5 * Distributed under the Thrift Software License
7 * See accompanying file LICENSE or visit the Thrift site at:
8 * http://developers.facebook.com/thrift/
11 * @author Mark Slee <mcslee@facebook.com>
15 * Data types that can be sent via Thrift
32 const LST
= 15; // N.B. cannot use LIST keyword in PHP!
38 * Message types for RPC
47 * NOTE(mcslee): This currently contains a ton of duplicated code from TBase
48 * because we need to save CPU cycles and this is not yet in an extension.
49 * Ideally we'd multiply-inherit TException from both Exception and Base, but
50 * that's not possible in PHP and there are no modules either, so for now we
51 * apologetically take a trip to HackTown.
53 * Can be called with standard Exception constructor (message, code) or with
54 * Thrift Base object constructor (spec, vals).
56 * @param mixed $p1 Message (string) or type-spec (array)
57 * @param mixed $p2 Code (integer) or values (array)
59 class TException
extends Exception
{
60 function __construct($p1=null, $p2=0) {
61 if (is_array($p1) && is_array($p2)) {
64 foreach ($spec as $fid => $fspec) {
66 if (isset($vals[$var])) {
67 $this->$var = $vals[$var];
71 parent
::__construct($p1, $p2);
75 static $tmethod = array(TType
::BOOL => 'Bool',
76 TType
::BYTE
=> 'Byte',
80 TType
::DOUBLE => 'Double',
81 TType
::STRING => 'String');
83 private function _readMap(&$var, $spec, $input) {
85 $ktype = $spec['ktype'];
86 $vtype = $spec['vtype'];
87 $kread = $vread = null;
88 if (isset(TBase
::$tmethod[$ktype])) {
89 $kread = 'read'.TBase
::$tmethod[$ktype];
91 $kspec = $spec['key'];
93 if (isset(TBase
::$tmethod[$vtype])) {
94 $vread = 'read'.TBase
::$tmethod[$vtype];
96 $vspec = $spec['val'];
99 $_ktype = $_vtype = $size = 0;
100 $xfer +
= $input->readMapBegin($_ktype, $_vtype, $size);
101 for ($i = 0; $i < $size; ++
$i) {
103 if ($kread !== null) {
104 $xfer +
= $input->$kread($key);
108 $class = $kspec['class'];
110 $xfer +
= $key->read($input);
113 $xfer +
= $this->_readMap($key, $kspec, $input);
116 $xfer +
= $this->_readList($key, $kspec, $input, false);
119 $xfer +
= $this->_readList($key, $kspec, $input, true);
123 if ($vread !== null) {
124 $xfer +
= $input->$vread($val);
128 $class = $vspec['class'];
130 $xfer +
= $val->read($input);
133 $xfer +
= $this->_readMap($val, $vspec, $input);
136 $xfer +
= $this->_readList($val, $vspec, $input, false);
139 $xfer +
= $this->_readList($val, $vspec, $input, true);
145 $xfer +
= $input->readMapEnd();
149 private function _readList(&$var, $spec, $input, $set=false) {
151 $etype = $spec['etype'];
152 $eread = $vread = null;
153 if (isset(TBase
::$tmethod[$etype])) {
154 $eread = 'read'.TBase
::$tmethod[$etype];
156 $espec = $spec['elem'];
161 $xfer +
= $input->readSetBegin($_etype, $size);
163 $xfer +
= $input->readListBegin($_etype, $size);
165 for ($i = 0; $i < $size; ++
$i) {
167 if ($eread !== null) {
168 $xfer +
= $input->$eread($elem);
170 $espec = $spec['elem'];
173 $class = $espec['class'];
174 $elem = new $class();
175 $xfer +
= $elem->read($input);
178 $xfer +
= $this->_readMap($elem, $espec, $input);
181 $xfer +
= $this->_readList($elem, $espec, $input, false);
184 $xfer +
= $this->_readList($elem, $espec, $input, true);
195 $xfer +
= $input->readSetEnd();
197 $xfer +
= $input->readListEnd();
202 protected function _read($class, $spec, $input) {
207 $xfer +
= $input->readStructBegin($fname);
208 $fast_binary = (bool)
209 is_a($input, 'TBinaryProtocolAccelerated') &&
210 function_exists('thrift_protocol_binary_deserialize');
213 $xfer +
= $input->readFieldBegin($fname, $ftype, $fid);
214 if ($ftype == TType
::STOP
) {
217 if (isset($spec[$fid])) {
218 $fspec = $spec[$fid];
219 $var = $fspec['var'];
220 if ($ftype == $fspec['type']) {
223 $class = isset($fspec['class']) ?
$fspec['class'] : '';
224 $this->$var = thrift_protocol_binary_deserialize($ftype, $input, $class);
226 if (isset(TBase
::$tmethod[$ftype])) {
227 $func = 'read'.TBase
::$tmethod[$ftype];
228 $xfer +
= $input->$func($this->$var);
232 $class = $fspec['class'];
233 $this->$var = new $class();
234 $xfer +
= $this->$var->read($input);
237 $xfer +
= $this->_readMap($this->$var, $fspec, $input);
240 $xfer +
= $this->_readList($this->$var, $fspec, $input, false);
243 $xfer +
= $this->_readList($this->$var, $fspec, $input, true);
249 $xfer +
= $input->skip($ftype);
252 $xfer +
= $input->skip($ftype);
254 $xfer +
= $input->readFieldEnd();
256 $xfer +
= $input->readStructEnd();
260 private function _writeMap($var, $spec, $output) {
262 $ktype = $spec['ktype'];
263 $vtype = $spec['vtype'];
264 $kwrite = $vwrite = null;
265 if (isset(TBase
::$tmethod[$ktype])) {
266 $kwrite = 'write'.TBase
::$tmethod[$ktype];
268 $kspec = $spec['key'];
270 if (isset(TBase
::$tmethod[$vtype])) {
271 $vwrite = 'write'.TBase
::$tmethod[$vtype];
273 $vspec = $spec['val'];
275 $xfer +
= $output->writeMapBegin($ktype, $vtype, count($var));
276 foreach ($var as $key => $val) {
277 if (isset($kwrite)) {
278 $xfer +
= $output->$kwrite($key);
282 $xfer +
= $key->write($output);
285 $xfer +
= $this->_writeMap($key, $kspec, $output);
288 $xfer +
= $this->_writeList($key, $kspec, $output, false);
291 $xfer +
= $this->_writeList($key, $kspec, $output, true);
295 if (isset($vwrite)) {
296 $xfer +
= $output->$vwrite($val);
300 $xfer +
= $val->write($output);
303 $xfer +
= $this->_writeMap($val, $vspec, $output);
306 $xfer +
= $this->_writeList($val, $vspec, $output, false);
309 $xfer +
= $this->_writeList($val, $vspec, $output, true);
314 $xfer +
= $output->writeMapEnd();
318 private function _writeList($var, $spec, $output, $set=false) {
320 $etype = $spec['etype'];
322 if (isset(TBase
::$tmethod[$etype])) {
323 $ewrite = 'write'.TBase
::$tmethod[$etype];
325 $espec = $spec['elem'];
328 $xfer +
= $output->writeSetBegin($etype, count($var));
330 $xfer +
= $output->writeListBegin($etype, count($var));
332 foreach ($var as $key => $val) {
333 $elem = $set ?
$key : $val;
334 if (isset($ewrite)) {
335 $xfer +
= $output->$ewrite($elem);
339 $xfer +
= $elem->write($output);
342 $xfer +
= $this->_writeMap($elem, $espec, $output);
345 $xfer +
= $this->_writeList($elem, $espec, $output, false);
348 $xfer +
= $this->_writeList($elem, $espec, $output, true);
354 $xfer +
= $output->writeSetEnd();
356 $xfer +
= $output->writeListEnd();
361 protected function _write($class, $spec, $output) {
363 $xfer +
= $output->writeStructBegin($class);
364 foreach ($spec as $fid => $fspec) {
365 $var = $fspec['var'];
366 if ($this->$var !== null) {
367 $ftype = $fspec['type'];
368 $xfer +
= $output->writeFieldBegin($var, $ftype, $fid);
369 if (isset(TBase
::$tmethod[$ftype])) {
370 $func = 'write'.TBase
::$tmethod[$ftype];
371 $xfer +
= $output->$func($this->$var);
375 $xfer +
= $this->$var->write($output);
378 $xfer +
= $this->_writeMap($this->$var, $fspec, $output);
381 $xfer +
= $this->_writeList($this->$var, $fspec, $output, false);
384 $xfer +
= $this->_writeList($this->$var, $fspec, $output, true);
388 $xfer +
= $output->writeFieldEnd();
391 $xfer +
= $output->writeFieldStop();
392 $xfer +
= $output->writeStructEnd();
399 * Base class from which other Thrift structs extend. This is so that we can
400 * cut back on the size of the generated code which is turning out to have a
401 * nontrivial cost just to load thanks to the wondrously abysmal implementation
402 * of PHP. Note that code is intentionally duplicated in here to avoid making
403 * function calls for every field or member of a container..
405 abstract class TBase
{
407 static $tmethod = array(TType
::BOOL => 'Bool',
408 TType
::BYTE
=> 'Byte',
412 TType
::DOUBLE => 'Double',
413 TType
::STRING => 'String');
415 abstract function read($input);
417 abstract function write($output);
419 public function __construct($spec=null, $vals=null) {
420 if (is_array($spec) && is_array($vals)) {
421 foreach ($spec as $fid => $fspec) {
422 $var = $fspec['var'];
423 if (isset($vals[$var])) {
424 $this->$var = $vals[$var];
430 private function _readMap(&$var, $spec, $input) {
432 $ktype = $spec['ktype'];
433 $vtype = $spec['vtype'];
434 $kread = $vread = null;
435 if (isset(TBase
::$tmethod[$ktype])) {
436 $kread = 'read'.TBase
::$tmethod[$ktype];
438 $kspec = $spec['key'];
440 if (isset(TBase
::$tmethod[$vtype])) {
441 $vread = 'read'.TBase
::$tmethod[$vtype];
443 $vspec = $spec['val'];
446 $_ktype = $_vtype = $size = 0;
447 $xfer +
= $input->readMapBegin($_ktype, $_vtype, $size);
448 for ($i = 0; $i < $size; ++
$i) {
450 if ($kread !== null) {
451 $xfer +
= $input->$kread($key);
455 $class = $kspec['class'];
457 $xfer +
= $key->read($input);
460 $xfer +
= $this->_readMap($elem, $kspec, $input);
463 $xfer +
= $this->_readList($elem, $kspec, $input, false);
466 $xfer +
= $this->_readList($elem, $kspec, $input, true);
470 if ($vread !== null) {
471 $xfer +
= $input->$vread($val);
475 $class = $vspec['class'];
477 $xfer +
= $val->read($input);
480 $xfer +
= $this->_readMap($val, $vspec, $input);
483 $xfer +
= $this->_readList($val, $vspec, $input, false);
486 $xfer +
= $this->_readList($val, $vspec, $input, true);
492 $xfer +
= $input->readMapEnd();
496 private function _readList(&$var, $spec, $input, $set=false) {
498 $etype = $spec['etype'];
499 $eread = $vread = null;
500 if (isset(TBase
::$tmethod[$etype])) {
501 $eread = 'read'.TBase
::$tmethod[$etype];
503 $espec = $spec['elem'];
508 $xfer +
= $input->readSetBegin($_etype, $size);
510 $xfer +
= $input->readListBegin($_etype, $size);
512 for ($i = 0; $i < $size; ++
$i) {
514 if ($eread !== null) {
515 $xfer +
= $input->$eread($elem);
517 $espec = $spec['elem'];
520 $class = $espec['class'];
521 $elem = new $class();
522 $xfer +
= $elem->read($input);
525 $xfer +
= $this->_readMap($key, $espec, $input);
528 $xfer +
= $this->_readList($key, $espec, $input, false);
531 $xfer +
= $this->_readList($key, $espec, $input, true);
542 $xfer +
= $input->readSetEnd();
544 $xfer +
= $input->readListEnd();
549 protected function _read($class, $spec, $input) {
554 $xfer +
= $input->readStructBegin($fname);
555 $fast_binary = (bool)
556 is_a($input, 'TBinaryProtocolAccelerated') &&
557 function_exists('thrift_protocol_binary_deserialize');
560 $xfer +
= $input->readFieldBegin($fname, $ftype, $fid);
561 if ($ftype == TType
::STOP
) {
564 if (isset($spec[$fid])) {
565 $fspec = $spec[$fid];
566 $var = $fspec['var'];
567 if ($ftype == $fspec['type']) {
570 $class = isset($fspec['class']) ?
$fspec['class'] : '';
571 $this->$var = thrift_protocol_binary_deserialize($ftype, $input, $class);
573 if (isset(TBase
::$tmethod[$ftype])) {
574 $func = 'read'.TBase
::$tmethod[$ftype];
575 $xfer +
= $input->$func($this->$var);
579 $class = $fspec['class'];
580 $this->$var = new $class();
581 $xfer +
= $this->$var->read($input);
584 $xfer +
= $this->_readMap($this->$var, $fspec, $input);
587 $xfer +
= $this->_readList($this->$var, $fspec, $input, false);
590 $xfer +
= $this->_readList($this->$var, $fspec, $input, true);
596 $xfer +
= $input->skip($ftype);
599 $xfer +
= $input->skip($ftype);
601 $xfer +
= $input->readFieldEnd();
603 $xfer +
= $input->readStructEnd();
607 private function _writeMap($var, $spec, $output) {
609 $ktype = $spec['ktype'];
610 $vtype = $spec['vtype'];
611 $kwrite = $vwrite = null;
612 if (isset(TBase
::$tmethod[$ktype])) {
613 $kwrite = 'write'.TBase
::$tmethod[$ktype];
615 $kspec = $spec['key'];
617 if (isset(TBase
::$tmethod[$vtype])) {
618 $vwrite = 'write'.TBase
::$tmethod[$vtype];
620 $vspec = $spec['val'];
622 $xfer +
= $output->writeMapBegin($ktype, $vtype, count($var));
623 foreach ($var as $key => $val) {
624 if (isset($kwrite)) {
625 $xfer +
= $output->$kwrite($key);
629 $xfer +
= $key->write($output);
632 $xfer +
= $this->_writeMap($key, $kspec, $output);
635 $xfer +
= $this->_writeList($key, $kspec, $output, false);
638 $xfer +
= $this->_writeList($key, $kspec, $output, true);
642 if (isset($vwrite)) {
643 $xfer +
= $output->$vwrite($val);
647 $xfer +
= $val->write($output);
650 $xfer +
= $this->_writeMap($val, $vspec, $output);
653 $xfer +
= $this->_writeList($val, $vspec, $output, false);
656 $xfer +
= $this->_writeList($val, $vspec, $output, true);
661 $xfer +
= $output->writeMapEnd();
665 private function _writeList($var, $spec, $output, $set=false) {
667 $etype = $spec['etype'];
669 if (isset(TBase
::$tmethod[$etype])) {
670 $ewrite = 'write'.TBase
::$tmethod[$etype];
672 $espec = $spec['elem'];
675 $xfer +
= $output->writeSetBegin($etype, count($var));
677 $xfer +
= $output->writeListBegin($etype, count($var));
679 foreach ($var as $key => $val) {
680 $elem = $set ?
$key : $val;
681 if (isset($ewrite)) {
682 $xfer +
= $output->$ewrite($elem);
686 $xfer +
= $elem->write($output);
689 $xfer +
= $this->_writeMap($elem, $espec, $output);
692 $xfer +
= $this->_writeList($elem, $espec, $output, false);
695 $xfer +
= $this->_writeList($elem, $espec, $output, true);
701 $xfer +
= $output->writeSetEnd();
703 $xfer +
= $output->writeListEnd();
708 protected function _write($class, $spec, $output) {
710 $xfer +
= $output->writeStructBegin($class);
711 foreach ($spec as $fid => $fspec) {
712 $var = $fspec['var'];
713 if ($this->$var !== null) {
714 $ftype = $fspec['type'];
715 $xfer +
= $output->writeFieldBegin($var, $ftype, $fid);
716 if (isset(TBase
::$tmethod[$ftype])) {
717 $func = 'write'.TBase
::$tmethod[$ftype];
718 $xfer +
= $output->$func($this->$var);
722 $xfer +
= $this->$var->write($output);
725 $xfer +
= $this->_writeMap($this->$var, $fspec, $output);
728 $xfer +
= $this->_writeList($this->$var, $fspec, $output, false);
731 $xfer +
= $this->_writeList($this->$var, $fspec, $output, true);
735 $xfer +
= $output->writeFieldEnd();
738 $xfer +
= $output->writeFieldStop();
739 $xfer +
= $output->writeStructEnd();
744 class TApplicationException
extends TException
{
746 array(1 => array('var' => 'message',
747 'type' => TType
::STRING),
748 2 => array('var' => 'code',
749 'type' => TType
::I32
));
752 const UNKNOWN_METHOD
= 1;
753 const INVALID_MESSAGE_TYPE
= 2;
754 const WRONG_METHOD_NAME
= 3;
755 const BAD_SEQUENCE_ID
= 4;
756 const MISSING_RESULT
= 5;
758 function __construct($message=null, $code=0) {
759 parent
::__construct($message, $code);
762 public function read($output) {
763 return $this->_read('TApplicationException', self
::$_TSPEC, $output);
766 public function write($output) {
768 $xfer +
= $output->writeStructBegin('TApplicationException');
769 if ($message = $this->getMessage()) {
770 $xfer +
= $output->writeFieldBegin('message', TType
::STRING, 1);
771 $xfer +
= $output->writeString($message);
772 $xfer +
= $output->writeFieldEnd();
774 if ($code = $this->getCode()) {
775 $xfer +
= $output->writeFieldBegin('type', TType
::I32
, 2);
776 $xfer +
= $output->writeI32($code);
777 $xfer +
= $output->writeFieldEnd();
779 $xfer +
= $output->writeFieldStop();
780 $xfer +
= $output->writeStructEnd();
786 * Set global THRIFT ROOT automatically via inclusion here
788 if (!isset($GLOBALS['THRIFT_ROOT'])) {
789 $GLOBALS['THRIFT_ROOT'] = dirname(__FILE__
);
791 include_once $GLOBALS['THRIFT_ROOT'].'/protocol/TProtocol.php';
792 include_once $GLOBALS['THRIFT_ROOT'].'/transport/TTransport.php';