1 // Copyright (c) 2006- Facebook
2 // Distributed under the Thrift Software License
4 // See accompanying file LICENSE or visit the Thrift site at:
5 // http://developers.facebook.com/thrift/
10 #include "t_php_generator.h"
14 * Prepares for file generation by opening up the necessary file output
17 * @param tprogram The program to generate
19 void t_php_generator::init_generator() {
20 // Make output directory
21 mkdir(get_out_dir().c_str(), S_IRWXU
| S_IRWXG
| S_IRWXO
);
24 string f_types_name
= get_out_dir()+program_name_
+"_types.php";
25 f_types_
.open(f_types_name
.c_str());
33 // Include other Thrift includes
34 const vector
<t_program
*>& includes
= program_
->get_includes();
35 for (size_t i
= 0; i
< includes
.size(); ++i
) {
36 string package
= includes
[i
]->get_name();
38 "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << package
<< "/" << package
<< "_types.php';" << endl
;
43 if (!program_
->get_consts().empty()) {
44 string f_consts_name
= get_out_dir()+program_name_
+"_constants.php";
45 f_consts_
.open(f_consts_name
.c_str());
49 "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" + program_name_
+ "/" + program_name_
+ "_types.php';" << endl
<<
51 "$GLOBALS['" << program_name_
<< "_CONSTANTS'] = array(); " << endl
<<
57 * Prints standard php includes
59 string
t_php_generator::php_includes() {
61 string("include_once $GLOBALS['THRIFT_ROOT'].'/Thrift.php';\n\n");
65 * Close up (or down) some filez.
67 void t_php_generator::close_generator() {
69 f_types_
<< "?>" << endl
;
72 if (!program_
->get_consts().empty()) {
73 f_consts_
<< "?>" << endl
;
79 * Generates a typedef. This is not done in PHP, types are all implicit.
81 * @param ttypedef The type definition
83 void t_php_generator::generate_typedef(t_typedef
* ttypedef
) {}
86 * Generates code for an enumerated type. Since define is expensive to lookup
87 * in PHP, we use a global array for this.
89 * @param tenum The enumeration
91 void t_php_generator::generate_enum(t_enum
* tenum
) {
93 "$GLOBALS['" << php_namespace(tenum
->get_program()) << "E_" << tenum
->get_name() << "'] = array(" << endl
;
95 vector
<t_enum_value
*> constants
= tenum
->get_constants();
96 vector
<t_enum_value
*>::iterator c_iter
;
98 for (c_iter
= constants
.begin(); c_iter
!= constants
.end(); ++c_iter
) {
99 if ((*c_iter
)->has_value()) {
100 value
= (*c_iter
)->get_value();
106 " '" << (*c_iter
)->get_name() << "' => " << value
<< "," << endl
;
110 ");" << endl
<< endl
;
113 // We're also doing it this way to see how it performs. It's more legible
114 // code but you can't do things like an 'extract' on it, which is a bit of
117 "final class " << php_namespace(tenum
->get_program()) << tenum
->get_name() << " {" << endl
;
121 for (c_iter
= constants
.begin(); c_iter
!= constants
.end(); ++c_iter
) {
122 if ((*c_iter
)->has_value()) {
123 value
= (*c_iter
)->get_value();
129 "const " << (*c_iter
)->get_name() << " = " << value
<< ";" << endl
;
133 "static public $__names = array(" << endl
;
135 for (c_iter
= constants
.begin(); c_iter
!= constants
.end(); ++c_iter
) {
136 if ((*c_iter
)->has_value()) {
137 value
= (*c_iter
)->get_value();
143 " " << value
<< " => '" << (*c_iter
)->get_name() << "'," << endl
;
149 f_types_
<< "}" << endl
<< endl
;
153 * Generate a constant value
155 void t_php_generator::generate_const(t_const
* tconst
) {
156 t_type
* type
= tconst
->get_type();
157 string name
= tconst
->get_name();
158 t_const_value
* value
= tconst
->get_value();
160 f_consts_
<< "$GLOBALS['" << program_name_
<< "_CONSTANTS']['" << name
<< "'] = ";
161 f_consts_
<< render_const_value(type
, value
);
162 f_consts_
<< ";" << endl
<< endl
;
166 * Prints the value of a constant with the given type. Note that type checking
167 * is NOT performed in this function as it is always run beforehand using the
168 * validate_types method in main.cc
170 string
t_php_generator::render_const_value(t_type
* type
, t_const_value
* value
) {
171 std::ostringstream out
;
172 type
= get_true_type(type
);
173 if (type
->is_base_type()) {
174 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
176 case t_base_type::TYPE_STRING
:
177 out
<< "'" << value
->get_string() << "'";
179 case t_base_type::TYPE_BOOL
:
180 out
<< (value
->get_integer() > 0 ? "true" : "false");
182 case t_base_type::TYPE_BYTE
:
183 case t_base_type::TYPE_I16
:
184 case t_base_type::TYPE_I32
:
185 case t_base_type::TYPE_I64
:
186 out
<< value
->get_integer();
188 case t_base_type::TYPE_DOUBLE
:
189 if (value
->get_type() == t_const_value::CV_INTEGER
) {
190 out
<< value
->get_integer();
192 out
<< value
->get_double();
196 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase
);
198 } else if (type
->is_enum()) {
199 indent(out
) << value
->get_integer();
200 } else if (type
->is_struct() || type
->is_xception()) {
201 out
<< "new " << php_namespace(type
->get_program()) << type
->get_name() << "(array(" << endl
;
203 const vector
<t_field
*>& fields
= ((t_struct
*)type
)->get_members();
204 vector
<t_field
*>::const_iterator f_iter
;
205 const map
<t_const_value
*, t_const_value
*>& val
= value
->get_map();
206 map
<t_const_value
*, t_const_value
*>::const_iterator v_iter
;
207 for (v_iter
= val
.begin(); v_iter
!= val
.end(); ++v_iter
) {
208 t_type
* field_type
= NULL
;
209 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
210 if ((*f_iter
)->get_name() == v_iter
->first
->get_string()) {
211 field_type
= (*f_iter
)->get_type();
214 if (field_type
== NULL
) {
215 throw "type error: " + type
->get_name() + " has no field " + v_iter
->first
->get_string();
218 out
<< render_const_value(g_type_string
, v_iter
->first
);
220 out
<< render_const_value(field_type
, v_iter
->second
);
225 } else if (type
->is_map()) {
226 t_type
* ktype
= ((t_map
*)type
)->get_key_type();
227 t_type
* vtype
= ((t_map
*)type
)->get_val_type();
228 out
<< "array(" << endl
;
230 const map
<t_const_value
*, t_const_value
*>& val
= value
->get_map();
231 map
<t_const_value
*, t_const_value
*>::const_iterator v_iter
;
232 for (v_iter
= val
.begin(); v_iter
!= val
.end(); ++v_iter
) {
234 out
<< render_const_value(ktype
, v_iter
->first
);
236 out
<< render_const_value(vtype
, v_iter
->second
);
241 } else if (type
->is_list() || type
->is_set()) {
243 if (type
->is_list()) {
244 etype
= ((t_list
*)type
)->get_elem_type();
246 etype
= ((t_set
*)type
)->get_elem_type();
248 out
<< "array(" << endl
;
250 const vector
<t_const_value
*>& val
= value
->get_list();
251 vector
<t_const_value
*>::const_iterator v_iter
;
252 for (v_iter
= val
.begin(); v_iter
!= val
.end(); ++v_iter
) {
254 out
<< render_const_value(etype
, *v_iter
);
255 if (type
->is_set()) {
269 void t_php_generator::generate_struct(t_struct
* tstruct
) {
270 generate_php_struct(tstruct
, false);
274 * Generates a struct definition for a thrift exception. Basically the same
275 * as a struct but extends the Exception class.
277 * @param txception The struct definition
279 void t_php_generator::generate_xception(t_struct
* txception
) {
280 generate_php_struct(txception
, true);
284 * Structs can be normal or exceptions.
286 void t_php_generator::generate_php_struct(t_struct
* tstruct
,
288 generate_php_struct_definition(f_types_
, tstruct
, is_exception
);
291 void t_php_generator::generate_php_type_spec(ofstream
& out
,
293 t
= get_true_type(t
);
294 indent(out
) << "'type' => " << type_to_enum(t
) << "," << endl
;
296 if (t
->is_base_type() || t
->is_enum()) {
297 // Noop, type is all we need
298 } else if (t
->is_struct() || t
->is_xception()) {
299 indent(out
) << "'class' => '" << php_namespace(t
->get_program()) << t
->get_name() <<"'," << endl
;
300 } else if (t
->is_map()) {
301 t_type
* ktype
= get_true_type(((t_map
*)t
)->get_key_type());
302 t_type
* vtype
= get_true_type(((t_map
*)t
)->get_val_type());
303 indent(out
) << "'ktype' => " << type_to_enum(ktype
) << "," << endl
;
304 indent(out
) << "'vtype' => " << type_to_enum(vtype
) << "," << endl
;
305 indent(out
) << "'key' => array(" << endl
;
307 generate_php_type_spec(out
, ktype
);
309 indent(out
) << ")," << endl
;
310 indent(out
) << "'val' => array(" << endl
;
312 generate_php_type_spec(out
, vtype
);
313 indent(out
) << ")," << endl
;
315 } else if (t
->is_list() || t
->is_set()) {
318 etype
= get_true_type(((t_list
*)t
)->get_elem_type());
320 etype
= get_true_type(((t_set
*)t
)->get_elem_type());
322 indent(out
) << "'etype' => " << type_to_enum(etype
) <<"," << endl
;
323 indent(out
) << "'elem' => array(" << endl
;
325 generate_php_type_spec(out
, etype
);
326 indent(out
) << ")," << endl
;
329 throw "compiler error: no type for php struct spec field";
335 * Generates the struct specification structure, which fully qualifies enough
336 * type information to generalize serialization routines.
338 void t_php_generator::generate_php_struct_spec(ofstream
& out
,
340 indent(out
) << "if (!isset(self::$_TSPEC)) {" << endl
;
343 indent(out
) << "self::$_TSPEC = array(" << endl
;
346 const vector
<t_field
*>& members
= tstruct
->get_members();
347 vector
<t_field
*>::const_iterator m_iter
;
348 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
) {
349 t_type
* t
= get_true_type((*m_iter
)->get_type());
350 indent(out
) << (*m_iter
)->get_key() << " => array(" << endl
;
353 indent() << "'var' => '" << (*m_iter
)->get_name() << "'," << endl
;
354 generate_php_type_spec(out
, t
);
355 indent(out
) << ")," << endl
;
360 indent(out
) << " );" << endl
;
362 indent(out
) << "}" << endl
;
366 void t_php_generator::generate_php_struct_definition(ofstream
& out
,
371 ofstream autoload_out
;
372 string f_struct
= program_name_
+"."+(tstruct
->get_name())+".php";
373 string f_struct_name
= get_out_dir()+f_struct
;
374 autoload_out
.open(f_struct_name
.c_str());
375 autoload_out
<< "<?php" << endl
;
376 _generate_php_struct_definition(autoload_out
, tstruct
, is_exception
);
377 autoload_out
<< endl
<< "?>" << endl
;
378 autoload_out
.close();
381 "$GLOBALS['THRIFT_AUTOLOAD']['" << lowercase(php_namespace(tstruct
->get_program()) + tstruct
->get_name()) << "'] = '" << program_name_
<< "/" << f_struct
<< "';" << endl
;
384 _generate_php_struct_definition(out
, tstruct
, is_exception
);
389 * Generates a struct definition for a thrift data type. This is nothing in PHP
390 * where the objects are all just associative arrays (unless of course we
391 * decide to start using objects for them...)
393 * @param tstruct The struct definition
395 void t_php_generator::_generate_php_struct_definition(ofstream
& out
,
398 const vector
<t_field
*>& members
= tstruct
->get_members();
399 vector
<t_field
*>::const_iterator m_iter
;
402 "class " << php_namespace(tstruct
->get_program()) << tstruct
->get_name();
404 out
<< " extends TException";
406 out
<< " extends TBase";
413 indent(out
) << "static $_TSPEC;" << endl
<< endl
;
416 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
) {
417 string dval
= "null";
418 t_type
* t
= get_true_type((*m_iter
)->get_type());
419 if ((*m_iter
)->get_value() != NULL
&& !(t
->is_struct() || t
->is_xception())) {
420 dval
= render_const_value((*m_iter
)->get_type(), (*m_iter
)->get_value());
423 "public $" << (*m_iter
)->get_name() << " = " << dval
<< ";" << endl
;
428 // Generate constructor from array
429 if (oop_
|| members
.size() > 0) {
430 string param
= (members
.size() > 0) ? "$vals=null" : "";
432 indent() << "public function __construct(" << param
<< ") {" << endl
;
436 generate_php_struct_spec(out
, tstruct
);
439 if (members
.size() > 0) {
440 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
) {
441 t_type
* t
= get_true_type((*m_iter
)->get_type());
442 if ((*m_iter
)->get_value() != NULL
&& (t
->is_struct() || t
->is_xception())) {
443 indent(out
) << "$this->" << (*m_iter
)->get_name() << " = " << render_const_value(t
, (*m_iter
)->get_value()) << ";" << endl
;
447 indent() << "if (is_array($vals)) {" << endl
;
450 out
<< indent() << "parent::construct(self::$_TSPEC, $vals);" << endl
;
452 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
) {
454 indent() << "if (isset($vals['" << (*m_iter
)->get_name() << "'])) {" << endl
<<
455 indent() << " $this->" << (*m_iter
)->get_name() << " = $vals['" << (*m_iter
)->get_name() << "'];" << endl
<<
456 indent() << "}" << endl
;
461 indent() << "}" << endl
;
468 indent() << "public function getName() {" << endl
<<
469 indent() << " return '" << tstruct
->get_name() << "';" << endl
<<
470 indent() << "}" << endl
<<
473 generate_php_struct_reader(out
, tstruct
);
474 generate_php_struct_writer(out
, tstruct
);
478 indent() << "}" << endl
<<
483 * Generates the read() method for a struct
485 void t_php_generator::generate_php_struct_reader(ofstream
& out
,
487 const vector
<t_field
*>& fields
= tstruct
->get_members();
488 vector
<t_field
*>::const_iterator f_iter
;
491 "public function read($input)" << endl
;
495 indent(out
) << "return $this->_read('" << tstruct
->get_name() << "', self::$_TSPEC, $input);" << endl
;
501 indent() << "$xfer = 0;" << endl
<<
502 indent() << "$fname = null;" << endl
<<
503 indent() << "$ftype = 0;" << endl
<<
504 indent() << "$fid = 0;" << endl
;
506 // Declare stack tmp variables
507 if (!binary_inline_
) {
509 "$xfer += $input->readStructBegin($fname);" << endl
;
512 // Loop over reading in fields
514 "while (true)" << endl
;
518 // Read beginning field marker
519 if (binary_inline_
) {
520 t_field
fftype(g_type_byte
, "ftype");
521 t_field
ffid(g_type_i16
, "fid");
522 generate_deserialize_field(out
, &fftype
);
524 indent() << "if ($ftype == TType::STOP) {" << endl
<<
525 indent() << " break;" << endl
<<
526 indent() << "}" << endl
;
527 generate_deserialize_field(out
, &ffid
);
530 "$xfer += $input->readFieldBegin($fname, $ftype, $fid);" << endl
;
531 // Check for field STOP marker and break
533 "if ($ftype == TType::STOP) {" << endl
;
542 // Switch statement on the field we are reading
544 "switch ($fid)" << endl
;
548 // Generate deserialization code for known cases
549 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
551 "case " << (*f_iter
)->get_key() << ":" << endl
;
553 indent(out
) << "if ($ftype == " << type_to_enum((*f_iter
)->get_type()) << ") {" << endl
;
555 generate_deserialize_field(out
, *f_iter
, "this->");
558 indent() << "} else {" << endl
;
559 if (binary_inline_
) {
560 indent(out
) << " $xfer += TProtocol::skipBinary($input, $ftype);" << endl
;
562 indent(out
) << " $xfer += $input->skip($ftype);" << endl
;
565 indent() << "}" << endl
<<
566 indent() << "break;" << endl
;
570 // In the default case we skip the field
571 indent(out
) << "default:" << endl
;
572 if (binary_inline_
) {
573 indent(out
) << " $xfer += TProtocol::skipBinary($input, $ftype);" << endl
;
575 indent(out
) << " $xfer += $input->skip($ftype);" << endl
;
577 indent(out
) << " break;" << endl
;
581 if (!binary_inline_
) {
582 // Read field end marker
584 "$xfer += $input->readFieldEnd();" << endl
;
589 if (!binary_inline_
) {
591 "$xfer += $input->readStructEnd();" << endl
;
595 "return $xfer;" << endl
;
599 indent() << "}" << endl
<<
604 * Generates the write() method for a struct
606 void t_php_generator::generate_php_struct_writer(ofstream
& out
,
608 string name
= tstruct
->get_name();
609 const vector
<t_field
*>& fields
= tstruct
->get_members();
610 vector
<t_field
*>::const_iterator f_iter
;
612 if (binary_inline_
) {
614 "public function write(&$output) {" << endl
;
617 "public function write($output) {" << endl
;
622 indent(out
) << "return $this->_write('" << tstruct
->get_name() << "', self::$_TSPEC, $output);" << endl
;
628 "$xfer = 0;" << endl
;
630 if (!binary_inline_
) {
632 "$xfer += $output->writeStructBegin('" << name
<< "');" << endl
;
635 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
637 indent() << "if ($this->" << (*f_iter
)->get_name() << " !== null) {" << endl
;
640 // Write field header
641 if (binary_inline_
) {
643 indent() << "$output .= pack('c', " << type_to_enum((*f_iter
)->get_type()) << ");" << endl
<<
644 indent() << "$output .= pack('n', " << (*f_iter
)->get_key() << ");" << endl
;
647 "$xfer += $output->writeFieldBegin(" <<
648 "'" << (*f_iter
)->get_name() << "', " <<
649 type_to_enum((*f_iter
)->get_type()) << ", " <<
650 (*f_iter
)->get_key() << ");" << endl
;
653 // Write field contents
654 generate_serialize_field(out
, *f_iter
, "this->");
656 // Write field closer
657 if (!binary_inline_
) {
659 "$xfer += $output->writeFieldEnd();" << endl
;
667 if (binary_inline_
) {
669 indent() << "$output .= pack('c', TType::STOP);" << endl
;
672 indent() << "$xfer += $output->writeFieldStop();" << endl
<<
673 indent() << "$xfer += $output->writeStructEnd();" << endl
;
677 indent() << "return $xfer;" << endl
;
681 indent() << "}" << endl
<<
686 * Generates a thrift service.
688 * @param tservice The service definition
690 void t_php_generator::generate_service(t_service
* tservice
) {
691 string f_service_name
= get_out_dir()+service_name_
+".php";
692 f_service_
.open(f_service_name
.c_str());
700 "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << program_name_
<< "/" << program_name_
<< "_types.php';" << endl
;
702 if (tservice
->get_extends() != NULL
) {
704 "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << tservice
->get_extends()->get_program()->get_name() << "/" << tservice
->get_extends()->get_name() << ".php';" << endl
;
710 // Generate the three main parts of the service (well, two for now in PHP)
711 generate_service_interface(tservice
);
713 generate_service_rest(tservice
);
715 generate_service_client(tservice
);
716 generate_service_helpers(tservice
);
718 generate_service_processor(tservice
);
721 // Close service file
722 f_service_
<< "?>" << endl
;
727 * Generates a service server definition.
729 * @param tservice The service to generate a server for.
731 void t_php_generator::generate_service_processor(t_service
* tservice
) {
732 // Generate the dispatch methods
733 vector
<t_function
*> functions
= tservice
->get_functions();
734 vector
<t_function
*>::iterator f_iter
;
737 string extends_processor
= "";
738 if (tservice
->get_extends() != NULL
) {
739 extends
= tservice
->get_extends()->get_name();
740 extends_processor
= " extends " + extends
+ "Processor";
743 // Generate the header portion
745 "class " << service_name_
<< "Processor" << extends_processor
<< " {" << endl
;
748 if (extends
.empty()) {
750 indent() << "protected $handler_ = null;" << endl
;
754 indent() << "public function __construct($handler) {" << endl
;
755 if (extends
.empty()) {
757 indent() << " $this->handler_ = $handler;" << endl
;
760 indent() << " parent::__construct($handler);" << endl
;
763 indent() << "}" << endl
<<
766 // Generate the server implementation
767 indent(f_service_
) <<
768 "public function process($input, $output) {" << endl
;
772 indent() << "$rseqid = 0;" << endl
<<
773 indent() << "$fname = null;" << endl
<<
774 indent() << "$mtype = 0;" << endl
<<
777 if (binary_inline_
) {
778 t_field
ffname(g_type_string
, "fname");
779 t_field
fmtype(g_type_byte
, "mtype");
780 t_field
fseqid(g_type_i32
, "rseqid");
781 generate_deserialize_field(f_service_
, &ffname
, "", true);
782 generate_deserialize_field(f_service_
, &fmtype
, "", true);
783 generate_deserialize_field(f_service_
, &fseqid
, "", true);
786 indent() << "$input->readMessageBegin($fname, $mtype, $rseqid);" << endl
;
789 // HOT: check for method implementation
791 indent() << "$methodname = 'process_'.$fname;" << endl
<<
792 indent() << "if (!method_exists($this, $methodname)) {" << endl
;
793 if (binary_inline_
) {
795 indent() << " throw new Exception('Function '.$fname.' not implemented.');" << endl
;
798 indent() << " $input->skip(TType::STRUCT);" << endl
<<
799 indent() << " $input->readMessageEnd();" << endl
<<
800 indent() << " $x = new TApplicationException('Function '.$fname.' not implemented.', TApplicationException::UNKNOWN_METHOD);" << endl
<<
801 indent() << " $output->writeMessageBegin($fname, TMessageType::EXCEPTION, $rseqid);" << endl
<<
802 indent() << " $x->write($output);" << endl
<<
803 indent() << " $output->writeMessageEnd();" << endl
<<
804 indent() << " $output->getTransport()->flush();" << endl
<<
805 indent() << " return;" << endl
;
808 indent() << "}" << endl
<<
809 indent() << "$this->$methodname($rseqid, $input, $output);" << endl
<<
810 indent() << "return true;" << endl
;
813 indent() << "}" << endl
<<
816 // Generate the process subfunctions
817 for (f_iter
= functions
.begin(); f_iter
!= functions
.end(); ++f_iter
) {
818 generate_process_function(tservice
, *f_iter
);
822 f_service_
<< "}" << endl
;
826 * Generates a process function definition.
828 * @param tfunction The function to write a dispatcher for
830 void t_php_generator::generate_process_function(t_service
* tservice
,
831 t_function
* tfunction
) {
833 indent(f_service_
) <<
834 "protected function process_" << tfunction
->get_name() <<
835 "($seqid, $input, $output) {" << endl
;
838 string argsname
= php_namespace(tservice
->get_program()) + service_name_
+ "_" + tfunction
->get_name() + "_args";
839 string resultname
= php_namespace(tservice
->get_program()) + service_name_
+ "_" + tfunction
->get_name() + "_result";
842 indent() << "$args = new " << argsname
<< "();" << endl
<<
843 indent() << "$args->read($input);" << endl
;
844 if (!binary_inline_
) {
846 indent() << "$input->readMessageEnd();" << endl
;
849 t_struct
* xs
= tfunction
->get_xceptions();
850 const std::vector
<t_field
*>& xceptions
= xs
->get_members();
851 vector
<t_field
*>::const_iterator x_iter
;
853 // Declare result for non async function
854 if (!tfunction
->is_async()) {
856 indent() << "$result = new " << resultname
<< "();" << endl
;
859 // Try block for a function with exceptions
860 if (xceptions
.size() > 0) {
862 indent() << "try {" << endl
;
866 // Generate the function call
867 t_struct
* arg_struct
= tfunction
->get_arglist();
868 const std::vector
<t_field
*>& fields
= arg_struct
->get_members();
869 vector
<t_field
*>::const_iterator f_iter
;
871 f_service_
<< indent();
872 if (!tfunction
->is_async() && !tfunction
->get_returntype()->is_void()) {
873 f_service_
<< "$result->success = ";
876 "$this->handler_->" << tfunction
->get_name() << "(";
878 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
884 f_service_
<< "$args->" << (*f_iter
)->get_name();
886 f_service_
<< ");" << endl
;
888 if (!tfunction
->is_async() && xceptions
.size() > 0) {
890 for (x_iter
= xceptions
.begin(); x_iter
!= xceptions
.end(); ++x_iter
) {
892 indent() << "} catch (" << php_namespace((*x_iter
)->get_type()->get_program()) << (*x_iter
)->get_type()->get_name() << " $" << (*x_iter
)->get_name() << ") {" << endl
;
893 if (!tfunction
->is_async()) {
896 indent() << "$result->" << (*x_iter
)->get_name() << " = $" << (*x_iter
)->get_name() << ";" << endl
;
898 f_service_
<< indent();
901 f_service_
<< "}" << endl
;
904 // Shortcut out here for async functions
905 if (tfunction
->is_async()) {
907 indent() << "return;" << endl
;
910 indent() << "}" << endl
;
914 // Serialize the request header
915 if (binary_inline_
) {
917 indent() << "$buff = pack('N', (0x80010000 | TMessageType::REPLY)); " << endl
<<
918 indent() << "$buff .= pack('N', strlen('" << tfunction
->get_name() << "'));" << endl
<<
919 indent() << "$buff .= '" << tfunction
->get_name() << "';" << endl
<<
920 indent() << "$buff .= pack('N', $seqid);" << endl
<<
921 indent() << "$result->write($buff);" << endl
<<
922 indent() << "$output->write($buff);" << endl
<<
923 indent() << "$output->flush();" << endl
;
926 indent() << "$output->writeMessageBegin('" << tfunction
->get_name() << "', TMessageType::REPLY, $seqid);" << endl
<<
927 indent() << "$result->write($output);" << endl
<<
928 indent() << "$output->getTransport()->flush();" << endl
;
934 indent() << "}" << endl
;
938 * Generates helper functions for a service.
940 * @param tservice The service to generate a header definition for
942 void t_php_generator::generate_service_helpers(t_service
* tservice
) {
943 vector
<t_function
*> functions
= tservice
->get_functions();
944 vector
<t_function
*>::iterator f_iter
;
947 "// HELPER FUNCTIONS AND STRUCTURES" << endl
<< endl
;
949 for (f_iter
= functions
.begin(); f_iter
!= functions
.end(); ++f_iter
) {
950 t_struct
* ts
= (*f_iter
)->get_arglist();
951 string name
= ts
->get_name();
952 ts
->set_name(service_name_
+ "_" + name
);
953 generate_php_struct_definition(f_service_
, ts
, false);
954 generate_php_function_helpers(*f_iter
);
960 * Generates a struct and helpers for a function.
962 * @param tfunction The function
964 void t_php_generator::generate_php_function_helpers(t_function
* tfunction
) {
965 if (!tfunction
->is_async()) {
966 t_struct
result(program_
, service_name_
+ "_" + tfunction
->get_name() + "_result");
967 t_field
success(tfunction
->get_returntype(), "success", 0);
968 if (!tfunction
->get_returntype()->is_void()) {
969 result
.append(&success
);
972 t_struct
* xs
= tfunction
->get_xceptions();
973 const vector
<t_field
*>& fields
= xs
->get_members();
974 vector
<t_field
*>::const_iterator f_iter
;
975 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
976 result
.append(*f_iter
);
979 generate_php_struct_definition(f_service_
, &result
, false);
984 * Generates a service interface definition.
986 * @param tservice The service to generate a header definition for
988 void t_php_generator::generate_service_interface(t_service
* tservice
) {
990 string extends_if
= "";
991 if (tservice
->get_extends() != NULL
) {
992 extends
= " extends " + tservice
->get_extends()->get_name();
993 extends_if
= " extends " + tservice
->get_extends()->get_name() + "If";
996 "interface " << service_name_
<< "If" << extends_if
<< " {" << endl
;
998 vector
<t_function
*> functions
= tservice
->get_functions();
999 vector
<t_function
*>::iterator f_iter
;
1000 for (f_iter
= functions
.begin(); f_iter
!= functions
.end(); ++f_iter
) {
1001 indent(f_service_
) <<
1002 "public function " << function_signature(*f_iter
) << ";" << endl
;
1006 "}" << endl
<< endl
;
1010 * Generates a REST interface
1012 void t_php_generator::generate_service_rest(t_service
* tservice
) {
1013 string extends
= "";
1014 string extends_if
= "";
1015 if (tservice
->get_extends() != NULL
) {
1016 extends
= " extends " + tservice
->get_extends()->get_name();
1017 extends_if
= " extends " + tservice
->get_extends()->get_name() + "Rest";
1020 "class " << service_name_
<< "Rest" << extends_if
<< " {" << endl
;
1023 if (extends
.empty()) {
1025 indent() << "protected $impl_;" << endl
<<
1030 indent() << "public function __construct($impl) {" << endl
<<
1031 indent() << " $this->impl_ = $impl;" << endl
<<
1032 indent() << "}" << endl
<<
1035 vector
<t_function
*> functions
= tservice
->get_functions();
1036 vector
<t_function
*>::iterator f_iter
;
1037 for (f_iter
= functions
.begin(); f_iter
!= functions
.end(); ++f_iter
) {
1038 indent(f_service_
) <<
1039 "public function " << (*f_iter
)->get_name() << "($request) {" << endl
;
1041 const vector
<t_field
*>& args
= (*f_iter
)->get_arglist()->get_members();
1042 vector
<t_field
*>::const_iterator a_iter
;
1043 for (a_iter
= args
.begin(); a_iter
!= args
.end(); ++a_iter
) {
1044 t_type
* atype
= get_true_type((*a_iter
)->get_type());
1045 string cast
= type_to_cast(atype
);
1046 string req
= "$request['" + (*a_iter
)->get_name() + "']";
1047 if (atype
->is_bool()) {
1049 indent() << "$" << (*a_iter
)->get_name() << " = " << cast
<< "(!empty(" << req
<< ") && (" << req
<< " !== 'false'));" << endl
;
1052 indent() << "$" << (*a_iter
)->get_name() << " = isset(" << req
<< ") ? " << cast
<< req
<< " : null;" << endl
;
1054 if (atype
->is_string() &&
1055 ((t_base_type
*)atype
)->is_string_list()) {
1057 indent() << "$" << (*a_iter
)->get_name() << " = explode(',', $" << (*a_iter
)->get_name() << ");" << endl
;
1058 } else if (atype
->is_map() || atype
->is_list()) {
1060 indent() << "$" << (*a_iter
)->get_name() << " = json_decode($" << (*a_iter
)->get_name() << ", true);" << endl
;
1061 } else if (atype
->is_set()) {
1063 indent() << "$" << (*a_iter
)->get_name() << " = array_fill_keys(json_decode($" << (*a_iter
)->get_name() << ", true), 1);" << endl
;
1064 } else if (atype
->is_struct() || atype
->is_xception()) {
1066 indent() << "$" << (*a_iter
)->get_name() << " = new " << php_namespace(atype
->get_program()) << atype
->get_name() << "(json_decode($" << (*a_iter
)->get_name() << ", true));" << endl
;
1070 indent() << "return $this->impl_->" << (*f_iter
)->get_name() << "(" << argument_list((*f_iter
)->get_arglist()) << ");" << endl
;
1072 indent(f_service_
) <<
1078 "}" << endl
<< endl
;
1081 void t_php_generator::generate_service_client(t_service
* tservice
) {
1084 ofstream autoload_out
;
1085 string f_struct
= program_name_
+"."+(tservice
->get_name())+".client.php";
1086 string f_struct_name
= get_out_dir()+f_struct
;
1087 autoload_out
.open(f_struct_name
.c_str());
1088 autoload_out
<< "<?php" << endl
;
1089 _generate_service_client(autoload_out
, tservice
);
1090 autoload_out
<< endl
<< "?>" << endl
;
1091 autoload_out
.close();
1094 "$GLOBALS['THRIFT_AUTOLOAD']['" << lowercase(service_name_
+ "Client") << "'] = '" << program_name_
<< "/" << f_struct
<< "';" << endl
;
1097 _generate_service_client(f_service_
, tservice
);
1102 * Generates a service client definition.
1104 * @param tservice The service to generate a server for.
1106 void t_php_generator::_generate_service_client(ofstream
& out
, t_service
* tservice
) {
1107 string extends
= "";
1108 string extends_client
= "";
1109 if (tservice
->get_extends() != NULL
) {
1110 extends
= tservice
->get_extends()->get_name();
1111 extends_client
= " extends " + extends
+ "Client";
1115 "class " << service_name_
<< "Client" << extends_client
<< " implements " << service_name_
<< "If {" << endl
;
1119 if (extends
.empty()) {
1121 indent() << "protected $input_ = null;" << endl
<<
1122 indent() << "protected $output_ = null;" << endl
<<
1125 indent() << "protected $seqid_ = 0;" << endl
<<
1129 // Constructor function
1131 indent() << "public function __construct($input, $output=null) {" << endl
;
1132 if (!extends
.empty()) {
1134 indent() << " parent::__construct($input, $output);" << endl
;
1137 indent() << " $this->input_ = $input;" << endl
<<
1138 indent() << " $this->output_ = $output ? $output : $input;" << endl
;
1141 indent() << "}" << endl
<< endl
;
1143 // Generate client method implementations
1144 vector
<t_function
*> functions
= tservice
->get_functions();
1145 vector
<t_function
*>::const_iterator f_iter
;
1146 for (f_iter
= functions
.begin(); f_iter
!= functions
.end(); ++f_iter
) {
1147 t_struct
* arg_struct
= (*f_iter
)->get_arglist();
1148 const vector
<t_field
*>& fields
= arg_struct
->get_members();
1149 vector
<t_field
*>::const_iterator fld_iter
;
1150 string funname
= (*f_iter
)->get_name();
1154 "public function " << function_signature(*f_iter
) << endl
;
1157 "$this->send_" << funname
<< "(";
1160 for (fld_iter
= fields
.begin(); fld_iter
!= fields
.end(); ++fld_iter
) {
1166 out
<< "$" << (*fld_iter
)->get_name();
1168 out
<< ");" << endl
;
1170 if (!(*f_iter
)->is_async()) {
1172 if (!(*f_iter
)->get_returntype()->is_void()) {
1176 "$this->recv_" << funname
<< "();" << endl
;
1182 "public function send_" << function_signature(*f_iter
) << endl
;
1185 std::string argsname
= php_namespace(tservice
->get_program()) + service_name_
+ "_" + (*f_iter
)->get_name() + "_args";
1187 // Serialize the request header
1188 if (binary_inline_
) {
1190 indent() << "$buff = pack('N', (0x80010000 | TMessageType::CALL));" << endl
<<
1191 indent() << "$buff .= pack('N', strlen('" << funname
<< "'));" << endl
<<
1192 indent() << "$buff .= '" << funname
<< "';" << endl
<<
1193 indent() << "$buff .= pack('N', $this->seqid_);" << endl
;
1196 indent() << "$this->output_->writeMessageBegin('" << (*f_iter
)->get_name() << "', TMessageType::CALL, $this->seqid_);" << endl
;
1200 indent() << "$args = new " << argsname
<< "();" << endl
;
1202 for (fld_iter
= fields
.begin(); fld_iter
!= fields
.end(); ++fld_iter
) {
1204 indent() << "$args->" << (*fld_iter
)->get_name() << " = $" << (*fld_iter
)->get_name() << ";" << endl
;
1207 // Write to the stream
1208 if (binary_inline_
) {
1210 indent() << "$args->write($buff);" << endl
<<
1211 indent() << "$this->output_->write($buff);" << endl
<<
1212 indent() << "$this->output_->flush();" << endl
;
1215 indent() << "$args->write($this->output_);" << endl
<<
1216 indent() << "$this->output_->writeMessageEnd();" << endl
<<
1217 indent() << "$this->output_->getTransport()->flush();" << endl
;
1223 if (!(*f_iter
)->is_async()) {
1224 std::string resultname
= php_namespace(tservice
->get_program()) + service_name_
+ "_" + (*f_iter
)->get_name() + "_result";
1225 t_struct
noargs(program_
);
1227 t_function
recv_function((*f_iter
)->get_returntype(),
1228 string("recv_") + (*f_iter
)->get_name(),
1233 indent() << "public function " << function_signature(&recv_function
) << endl
;
1237 indent() << "$rseqid = 0;" << endl
<<
1238 indent() << "$fname = null;" << endl
<<
1239 indent() << "$mtype = 0;" << endl
<<
1242 if (binary_inline_
) {
1243 t_field
ffname(g_type_string
, "fname");
1244 t_field
fseqid(g_type_i32
, "rseqid");
1246 indent() << "$ver = unpack('N', $this->input_->readAll(4));" << endl
<<
1247 indent() << "$ver = $ver[1];" << endl
<<
1248 indent() << "$mtype = $ver & 0xff;" << endl
<<
1249 indent() << "$ver = $ver & 0xffff0000;" << endl
<<
1250 indent() << "if ($ver != 0x80010000) throw new TProtocolException('Bad version identifier: '.$ver, TProtocolException::BAD_VERSION);" << endl
;
1251 generate_deserialize_field(out
, &ffname
, "", true);
1252 generate_deserialize_field(out
, &fseqid
, "", true);
1255 indent() << "$this->input_->readMessageBegin($fname, $mtype, $rseqid);" << endl
<<
1256 indent() << "if ($mtype == TMessageType::EXCEPTION) {" << endl
<<
1257 indent() << " $x = new TApplicationException();" << endl
<<
1258 indent() << " $x->read($this->input_);" << endl
<<
1259 indent() << " $this->input_->readMessageEnd();" << endl
<<
1260 indent() << " throw $x;" << endl
<<
1261 indent() << "}" << endl
;
1265 indent() << "$result = new " << resultname
<< "();" << endl
<<
1266 indent() << "$result->read($this->input_);" << endl
;
1268 if (!binary_inline_
) {
1270 indent() << "$this->input_->readMessageEnd();" << endl
<<
1274 // Careful, only return result if not a void function
1275 if (!(*f_iter
)->get_returntype()->is_void()) {
1277 indent() << "if ($result->success !== null) {" << endl
<<
1278 indent() << " return $result->success;" << endl
<<
1279 indent() << "}" << endl
;
1282 t_struct
* xs
= (*f_iter
)->get_xceptions();
1283 const std::vector
<t_field
*>& xceptions
= xs
->get_members();
1284 vector
<t_field
*>::const_iterator x_iter
;
1285 for (x_iter
= xceptions
.begin(); x_iter
!= xceptions
.end(); ++x_iter
) {
1287 indent() << "if ($result->" << (*x_iter
)->get_name() << " !== null) {" << endl
<<
1288 indent() << " throw $result->" << (*x_iter
)->get_name() << ";" << endl
<<
1289 indent() << "}" << endl
;
1292 // Careful, only return _result if not a void function
1293 if ((*f_iter
)->get_returntype()->is_void()) {
1298 indent() << "throw new Exception(\"" << (*f_iter
)->get_name() << " failed: unknown result\");" << endl
;
1310 "}" << endl
<< endl
;
1314 * Deserializes a field of any type.
1316 void t_php_generator::generate_deserialize_field(ofstream
&out
,
1320 t_type
* type
= get_true_type(tfield
->get_type());
1322 if (type
->is_void()) {
1323 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
1324 prefix
+ tfield
->get_name();
1327 string name
= prefix
+ tfield
->get_name();
1329 if (type
->is_struct() || type
->is_xception()) {
1330 generate_deserialize_struct(out
,
1335 if (type
->is_container()) {
1336 generate_deserialize_container(out
, type
, name
);
1337 } else if (type
->is_base_type() || type
->is_enum()) {
1339 out
<< indent() << "if (($input instanceof TProtocol::$TBINARYPROTOCOLACCELERATED) && function_exists('thrift_protocol_binary_deserialize')) {" << endl
;
1342 if (type
->is_enum()) {
1345 ttype_name
= t_base_type::t_base_name(static_cast<t_base_type
*>(type
)->get_base());
1346 for (size_t _s
= 0; _s
< ttype_name
.size(); ++_s
) {
1347 ttype_name
[_s
] = toupper(ttype_name
[_s
]);
1351 out
<< indent() << "$" << name
<< " = thrift_protocol_binary_deserialize(TType::" << ttype_name
<< ", $input);" << endl
;
1353 out
<< indent() << "} else {" << endl
;
1357 if (binary_inline_
) {
1358 std::string itrans
= (inclass
? "$this->input_" : "$input");
1360 if (type
->is_base_type()) {
1361 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
1363 case t_base_type::TYPE_VOID
:
1364 throw "compiler error: cannot serialize void field in a struct: " +
1367 case t_base_type::TYPE_STRING
:
1369 indent() << "$len = unpack('N', " << itrans
<< "->readAll(4));" << endl
<<
1370 indent() << "$len = $len[1];" << endl
<<
1371 indent() << "if ($len > 0x7fffffff) {" << endl
<<
1372 indent() << " $len = 0 - (($len - 1) ^ 0xffffffff);" << endl
<<
1373 indent() << "}" << endl
<<
1374 indent() << "$" << name
<< " = " << itrans
<< "->readAll($len);" << endl
;
1376 case t_base_type::TYPE_BOOL
:
1378 indent() << "$" << name
<< " = unpack('c', " << itrans
<< "->readAll(1));" << endl
<<
1379 indent() << "$" << name
<< " = (bool)$" << name
<< "[1];" << endl
;
1381 case t_base_type::TYPE_BYTE
:
1383 indent() << "$" << name
<< " = unpack('c', " << itrans
<< "->readAll(1));" << endl
<<
1384 indent() << "$" << name
<< " = $" << name
<< "[1];" << endl
;
1386 case t_base_type::TYPE_I16
:
1388 indent() << "$val = unpack('n', " << itrans
<< "->readAll(2));" << endl
<<
1389 indent() << "$val = $val[1];" << endl
<<
1390 indent() << "if ($val > 0x7fff) {" << endl
<<
1391 indent() << " $val = 0 - (($val - 1) ^ 0xffff);" << endl
<<
1392 indent() << "}" << endl
<<
1393 indent() << "$" << name
<< " = $val;" << endl
;
1395 case t_base_type::TYPE_I32
:
1397 indent() << "$val = unpack('N', " << itrans
<< "->readAll(4));" << endl
<<
1398 indent() << "$val = $val[1];" << endl
<<
1399 indent() << "if ($val > 0x7fffffff) {" << endl
<<
1400 indent() << " $val = 0 - (($val - 1) ^ 0xffffffff);" << endl
<<
1401 indent() << "}" << endl
<<
1402 indent() << "$" << name
<< " = $val;" << endl
;
1404 case t_base_type::TYPE_I64
:
1406 indent() << "$arr = unpack('N2', " << itrans
<< "->readAll(8));" << endl
<<
1407 indent() << "if ($arr[1] & 0x80000000) {" << endl
<<
1408 indent() << " $arr[1] = $arr[1] ^ 0xFFFFFFFF;" << endl
<<
1409 indent() << " $arr[2] = $arr[2] ^ 0xFFFFFFFF;" << endl
<<
1410 indent() << " $" << name
<< " = 0 - $arr[1]*4294967296 - $arr[2] - 1;" << endl
<<
1411 indent() << "} else {" << endl
<<
1412 indent() << " $" << name
<< " = $arr[1]*4294967296 + $arr[2];" << endl
<<
1413 indent() << "}" << endl
;
1415 case t_base_type::TYPE_DOUBLE
:
1417 indent() << "$arr = unpack('d', strrev(" << itrans
<< "->readAll(8)));" << endl
<<
1418 indent() << "$" << name
<< " = $arr[1];" << endl
;
1421 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase
) + tfield
->get_name();
1423 } else if (type
->is_enum()) {
1425 indent() << "$val = unpack('N', " << itrans
<< "->readAll(4));" << endl
<<
1426 indent() << "$val = $val[1];" << endl
<<
1427 indent() << "if ($val > 0x7fffffff) {" << endl
<<
1428 indent() << " $val = 0 - (($val - 1) ^ 0xffffffff);" << endl
<<
1429 indent() << "}" << endl
<<
1430 indent() << "$" << name
<< " = $val;" << endl
;
1435 "$xfer += $input->";
1437 if (type
->is_base_type()) {
1438 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
1440 case t_base_type::TYPE_VOID
:
1441 throw "compiler error: cannot serialize void field in a struct: " +
1444 case t_base_type::TYPE_STRING
:
1445 out
<< "readString($" << name
<< ");";
1447 case t_base_type::TYPE_BOOL
:
1448 out
<< "readBool($" << name
<< ");";
1450 case t_base_type::TYPE_BYTE
:
1451 out
<< "readByte($" << name
<< ");";
1453 case t_base_type::TYPE_I16
:
1454 out
<< "readI16($" << name
<< ");";
1456 case t_base_type::TYPE_I32
:
1457 out
<< "readI32($" << name
<< ");";
1459 case t_base_type::TYPE_I64
:
1460 out
<< "readI64($" << name
<< ");";
1462 case t_base_type::TYPE_DOUBLE
:
1463 out
<< "readDouble($" << name
<< ");";
1466 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase
);
1468 } else if (type
->is_enum()) {
1469 out
<< "readI32($" << name
<< ");";
1473 out
<< indent() << "}" << endl
;
1476 printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
1477 tfield
->get_name().c_str(), type
->get_name().c_str());
1483 * Generates an unserializer for a variable. This makes two key assumptions,
1484 * first that there is a const char* variable named data that points to the
1485 * buffer for deserialization, and that there is a variable protocol which
1486 * is a reference to a TProtocol serialization object.
1488 void t_php_generator::generate_deserialize_struct(ofstream
&out
,
1492 indent() << "$" << prefix
<< " = new " << php_namespace(tstruct
->get_program()) << tstruct
->get_name() << "();" << endl
<<
1493 indent() << "$xfer += $" << prefix
<< "->read($input);" << endl
;
1496 void t_php_generator::generate_deserialize_container(ofstream
&out
,
1499 out
<< indent() << "if (($input instanceof TProtocol::$TBINARYPROTOCOLACCELERATED) && function_exists('thrift_protocol_binary_deserialize'))" << endl
;
1503 t_type
* tvaluetype
= NULL
;
1504 if (ttype
->is_map()) {
1506 tvaluetype
= reinterpret_cast<t_map
*>(ttype
)->get_val_type();
1507 } else if (ttype
->is_set()) {
1509 tvaluetype
= reinterpret_cast<t_set
*>(ttype
)->get_elem_type();
1510 } else if (ttype
->is_list()) {
1512 tvaluetype
= reinterpret_cast<t_list
*>(ttype
)->get_elem_type();
1514 if (tvaluetype
->is_struct()) {
1515 out
<< indent() << "$" << prefix
<< " = thrift_protocol_binary_deserialize(TType::" << ttype_name
<< ", $input, '" << tvaluetype
->get_name() << "');" << endl
;
1517 out
<< indent() << "$" << prefix
<< " = thrift_protocol_binary_deserialize(TType::" << ttype_name
<< ", $input);" << endl
;
1520 out
<< indent() << "else" << endl
;
1523 string size
= tmp("_size");
1524 string ktype
= tmp("_ktype");
1525 string vtype
= tmp("_vtype");
1526 string etype
= tmp("_etype");
1528 t_field
fsize(g_type_i32
, size
);
1529 t_field
fktype(g_type_byte
, ktype
);
1530 t_field
fvtype(g_type_byte
, vtype
);
1531 t_field
fetype(g_type_byte
, etype
);
1534 indent() << "$" << prefix
<< " = array();" << endl
<<
1535 indent() << "$" << size
<< " = 0;" << endl
;
1537 // Declare variables, read header
1538 if (ttype
->is_map()) {
1540 indent() << "$" << ktype
<< " = 0;" << endl
<<
1541 indent() << "$" << vtype
<< " = 0;" << endl
;
1542 if (binary_inline_
) {
1543 generate_deserialize_field(out
, &fktype
);
1544 generate_deserialize_field(out
, &fvtype
);
1545 generate_deserialize_field(out
, &fsize
);
1548 indent() << "$xfer += $input->readMapBegin(" <<
1549 "$" << ktype
<< ", $" << vtype
<< ", $" << size
<< ");" << endl
;
1551 } else if (ttype
->is_set()) {
1552 if (binary_inline_
) {
1553 generate_deserialize_field(out
, &fetype
);
1554 generate_deserialize_field(out
, &fsize
);
1557 indent() << "$" << etype
<< " = 0;" << endl
<<
1558 indent() << "$xfer += $input->readSetBegin(" <<
1559 "$" << etype
<< ", $" << size
<< ");" << endl
;
1561 } else if (ttype
->is_list()) {
1562 if (binary_inline_
) {
1563 generate_deserialize_field(out
, &fetype
);
1564 generate_deserialize_field(out
, &fsize
);
1567 indent() << "$" << etype
<< " = 0;" << endl
<<
1568 indent() << "$xfer += $input->readListBegin(" <<
1569 "$" << etype
<< ", $" << size
<< ");" << endl
;
1573 // For loop iterates over elements
1574 string i
= tmp("_i");
1577 i
<< " = 0; $" << i
<< " < $" << size
<< "; ++$" << i
<< ")" << endl
;
1581 if (ttype
->is_map()) {
1582 generate_deserialize_map_element(out
, (t_map
*)ttype
, prefix
);
1583 } else if (ttype
->is_set()) {
1584 generate_deserialize_set_element(out
, (t_set
*)ttype
, prefix
);
1585 } else if (ttype
->is_list()) {
1586 generate_deserialize_list_element(out
, (t_list
*)ttype
, prefix
);
1591 if (!binary_inline_
) {
1592 // Read container end
1593 if (ttype
->is_map()) {
1594 indent(out
) << "$xfer += $input->readMapEnd();" << endl
;
1595 } else if (ttype
->is_set()) {
1596 indent(out
) << "$xfer += $input->readSetEnd();" << endl
;
1597 } else if (ttype
->is_list()) {
1598 indent(out
) << "$xfer += $input->readListEnd();" << endl
;
1607 * Generates code to deserialize a map
1609 void t_php_generator::generate_deserialize_map_element(ofstream
&out
,
1612 string key
= tmp("key");
1613 string val
= tmp("val");
1614 t_field
fkey(tmap
->get_key_type(), key
);
1615 t_field
fval(tmap
->get_val_type(), val
);
1618 declare_field(&fkey
, true, true) << endl
;
1620 declare_field(&fval
, true, true) << endl
;
1622 generate_deserialize_field(out
, &fkey
);
1623 generate_deserialize_field(out
, &fval
);
1626 "$" << prefix
<< "[$" << key
<< "] = $" << val
<< ";" << endl
;
1629 void t_php_generator::generate_deserialize_set_element(ofstream
&out
,
1632 string elem
= tmp("elem");
1633 t_field
felem(tset
->get_elem_type(), elem
);
1636 "$" << elem
<< " = null;" << endl
;
1638 generate_deserialize_field(out
, &felem
);
1641 "$" << prefix
<< "[$" << elem
<< "] = true;" << endl
;
1644 void t_php_generator::generate_deserialize_list_element(ofstream
&out
,
1647 string elem
= tmp("elem");
1648 t_field
felem(tlist
->get_elem_type(), elem
);
1651 "$" << elem
<< " = null;" << endl
;
1653 generate_deserialize_field(out
, &felem
);
1656 "$" << prefix
<< " []= $" << elem
<< ";" << endl
;
1661 * Serializes a field of any type.
1663 * @param tfield The field to serialize
1664 * @param prefix Name to prepend to field name
1666 void t_php_generator::generate_serialize_field(ofstream
&out
,
1669 t_type
* type
= get_true_type(tfield
->get_type());
1671 // Do nothing for void types
1672 if (type
->is_void()) {
1673 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
1674 prefix
+ tfield
->get_name();
1677 if (type
->is_struct() || type
->is_xception()) {
1678 generate_serialize_struct(out
,
1680 prefix
+ tfield
->get_name());
1681 } else if (type
->is_container()) {
1682 generate_serialize_container(out
,
1684 prefix
+ tfield
->get_name());
1685 } else if (type
->is_base_type() || type
->is_enum()) {
1687 string name
= prefix
+ tfield
->get_name();
1689 if (binary_inline_
) {
1690 if (type
->is_base_type()) {
1691 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
1693 case t_base_type::TYPE_VOID
:
1695 "compiler error: cannot serialize void field in a struct: " + name
;
1697 case t_base_type::TYPE_STRING
:
1699 indent() << "$output .= pack('N', strlen($" << name
<< "));" << endl
<<
1700 indent() << "$output .= $" << name
<< ";" << endl
;
1702 case t_base_type::TYPE_BOOL
:
1704 indent() << "$output .= pack('c', $" << name
<< " ? 1 : 0);" << endl
;
1706 case t_base_type::TYPE_BYTE
:
1708 indent() << "$output .= pack('c', $" << name
<< ");" << endl
;
1710 case t_base_type::TYPE_I16
:
1712 indent() << "$output .= pack('n', $" << name
<< ");" << endl
;
1714 case t_base_type::TYPE_I32
:
1716 indent() << "$output .= pack('N', $" << name
<< ");" << endl
;
1718 case t_base_type::TYPE_I64
:
1720 indent() << "$output .= pack('N2', $" << name
<< " >> 32, $" << name
<< " & 0xFFFFFFFF);" << endl
;
1722 case t_base_type::TYPE_DOUBLE
:
1724 indent() << "$output .= strrev(pack('d', $" << name
<< "));" << endl
;
1727 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase
);
1729 } else if (type
->is_enum()) {
1731 indent() << "$output .= pack('N', $" << name
<< ");" << endl
;
1736 "$xfer += $output->";
1738 if (type
->is_base_type()) {
1739 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
1741 case t_base_type::TYPE_VOID
:
1743 "compiler error: cannot serialize void field in a struct: " + name
;
1745 case t_base_type::TYPE_STRING
:
1746 out
<< "writeString($" << name
<< ");";
1748 case t_base_type::TYPE_BOOL
:
1749 out
<< "writeBool($" << name
<< ");";
1751 case t_base_type::TYPE_BYTE
:
1752 out
<< "writeByte($" << name
<< ");";
1754 case t_base_type::TYPE_I16
:
1755 out
<< "writeI16($" << name
<< ");";
1757 case t_base_type::TYPE_I32
:
1758 out
<< "writeI32($" << name
<< ");";
1760 case t_base_type::TYPE_I64
:
1761 out
<< "writeI64($" << name
<< ");";
1763 case t_base_type::TYPE_DOUBLE
:
1764 out
<< "writeDouble($" << name
<< ");";
1767 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase
);
1769 } else if (type
->is_enum()) {
1770 out
<< "writeI32($" << name
<< ");";
1775 printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
1777 tfield
->get_name().c_str(),
1778 type
->get_name().c_str());
1783 * Serializes all the members of a struct.
1785 * @param tstruct The struct to serialize
1786 * @param prefix String prefix to attach to all fields
1788 void t_php_generator::generate_serialize_struct(ofstream
&out
,
1792 "$xfer += $" << prefix
<< "->write($output);" << endl
;
1796 * Writes out a container
1798 void t_php_generator::generate_serialize_container(ofstream
&out
,
1803 if (ttype
->is_map()) {
1804 if (binary_inline_
) {
1806 indent() << "$output .= pack('c', " << type_to_enum(((t_map
*)ttype
)->get_key_type()) << ");" << endl
<<
1807 indent() << "$output .= pack('c', " << type_to_enum(((t_map
*)ttype
)->get_val_type()) << ");" << endl
<<
1808 indent() << "$output .= strrev(pack('l', count($" << prefix
<< ")));" << endl
;
1811 "$output->writeMapBegin(" <<
1812 type_to_enum(((t_map
*)ttype
)->get_key_type()) << ", " <<
1813 type_to_enum(((t_map
*)ttype
)->get_val_type()) << ", " <<
1814 "count($" << prefix
<< "));" << endl
;
1816 } else if (ttype
->is_set()) {
1817 if (binary_inline_
) {
1819 indent() << "$output .= pack('c', " << type_to_enum(((t_set
*)ttype
)->get_elem_type()) << ");" << endl
<<
1820 indent() << "$output .= strrev(pack('l', count($" << prefix
<< ")));" << endl
;
1824 "$output->writeSetBegin(" <<
1825 type_to_enum(((t_set
*)ttype
)->get_elem_type()) << ", " <<
1826 "count($" << prefix
<< "));" << endl
;
1828 } else if (ttype
->is_list()) {
1829 if (binary_inline_
) {
1831 indent() << "$output .= pack('c', " << type_to_enum(((t_list
*)ttype
)->get_elem_type()) << ");" << endl
<<
1832 indent() << "$output .= strrev(pack('l', count($" << prefix
<< ")));" << endl
;
1836 "$output->writeListBegin(" <<
1837 type_to_enum(((t_list
*)ttype
)->get_elem_type()) << ", " <<
1838 "count($" << prefix
<< "));" << endl
;
1844 if (ttype
->is_map()) {
1845 string kiter
= tmp("kiter");
1846 string viter
= tmp("viter");
1848 "foreach ($" << prefix
<< " as " <<
1849 "$" << kiter
<< " => $" << viter
<< ")" << endl
;
1851 generate_serialize_map_element(out
, (t_map
*)ttype
, kiter
, viter
);
1853 } else if (ttype
->is_set()) {
1854 string iter
= tmp("iter");
1856 "foreach ($" << prefix
<< " as $" << iter
<< " => $true)" << endl
;
1858 generate_serialize_set_element(out
, (t_set
*)ttype
, iter
);
1860 } else if (ttype
->is_list()) {
1861 string iter
= tmp("iter");
1863 "foreach ($" << prefix
<< " as $" << iter
<< ")" << endl
;
1865 generate_serialize_list_element(out
, (t_list
*)ttype
, iter
);
1871 if (!binary_inline_
) {
1872 if (ttype
->is_map()) {
1874 "$output->writeMapEnd();" << endl
;
1875 } else if (ttype
->is_set()) {
1877 "$output->writeSetEnd();" << endl
;
1878 } else if (ttype
->is_list()) {
1880 "$output->writeListEnd();" << endl
;
1888 * Serializes the members of a map.
1891 void t_php_generator::generate_serialize_map_element(ofstream
&out
,
1895 t_field
kfield(tmap
->get_key_type(), kiter
);
1896 generate_serialize_field(out
, &kfield
, "");
1898 t_field
vfield(tmap
->get_val_type(), viter
);
1899 generate_serialize_field(out
, &vfield
, "");
1903 * Serializes the members of a set.
1905 void t_php_generator::generate_serialize_set_element(ofstream
&out
,
1908 t_field
efield(tset
->get_elem_type(), iter
);
1909 generate_serialize_field(out
, &efield
, "");
1913 * Serializes the members of a list.
1915 void t_php_generator::generate_serialize_list_element(ofstream
&out
,
1918 t_field
efield(tlist
->get_elem_type(), iter
);
1919 generate_serialize_field(out
, &efield
, "");
1923 * Declares a field, which may include initialization as necessary.
1925 * @param ttype The type
1927 string
t_php_generator::declare_field(t_field
* tfield
, bool init
, bool obj
) {
1928 string result
= "$" + tfield
->get_name();
1930 t_type
* type
= get_true_type(tfield
->get_type());
1931 if (type
->is_base_type()) {
1932 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
1934 case t_base_type::TYPE_VOID
:
1936 case t_base_type::TYPE_STRING
:
1939 case t_base_type::TYPE_BOOL
:
1940 result
+= " = false";
1942 case t_base_type::TYPE_BYTE
:
1943 case t_base_type::TYPE_I16
:
1944 case t_base_type::TYPE_I32
:
1945 case t_base_type::TYPE_I64
:
1948 case t_base_type::TYPE_DOUBLE
:
1952 throw "compiler error: no PHP initializer for base type " + t_base_type::t_base_name(tbase
);
1954 } else if (type
->is_enum()) {
1956 } else if (type
->is_container()) {
1957 result
+= " = array()";
1958 } else if (type
->is_struct() || type
->is_xception()) {
1960 result
+= " = new " + php_namespace(type
->get_program()) + type
->get_name() + "()";
1962 result
+= " = null";
1966 return result
+ ";";
1970 * Renders a function signature of the form 'type name(args)'
1972 * @param tfunction Function definition
1973 * @return String of rendered function definition
1975 string
t_php_generator::function_signature(t_function
* tfunction
,
1978 prefix
+ tfunction
->get_name() +
1979 "(" + argument_list(tfunction
->get_arglist()) + ")";
1983 * Renders a field list
1985 string
t_php_generator::argument_list(t_struct
* tstruct
) {
1988 const vector
<t_field
*>& fields
= tstruct
->get_members();
1989 vector
<t_field
*>::const_iterator f_iter
;
1991 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
1997 result
+= "$" + (*f_iter
)->get_name();
2003 * Gets a typecast string for a particular type.
2005 string
t_php_generator::type_to_cast(t_type
* type
) {
2006 if (type
->is_base_type()) {
2007 t_base_type
* btype
= (t_base_type
*)type
;
2008 switch (btype
->get_base()) {
2009 case t_base_type::TYPE_BOOL
:
2011 case t_base_type::TYPE_BYTE
:
2012 case t_base_type::TYPE_I16
:
2013 case t_base_type::TYPE_I32
:
2014 case t_base_type::TYPE_I64
:
2016 case t_base_type::TYPE_DOUBLE
:
2018 case t_base_type::TYPE_STRING
:
2023 } else if (type
->is_enum()) {
2030 * Converts the parse type to a C++ enum string for the given type.
2032 string
t_php_generator ::type_to_enum(t_type
* type
) {
2033 type
= get_true_type(type
);
2035 if (type
->is_base_type()) {
2036 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
2038 case t_base_type::TYPE_VOID
:
2039 throw "NO T_VOID CONSTRUCT";
2040 case t_base_type::TYPE_STRING
:
2041 return "TType::STRING";
2042 case t_base_type::TYPE_BOOL
:
2043 return "TType::BOOL";
2044 case t_base_type::TYPE_BYTE
:
2045 return "TType::BYTE";
2046 case t_base_type::TYPE_I16
:
2047 return "TType::I16";
2048 case t_base_type::TYPE_I32
:
2049 return "TType::I32";
2050 case t_base_type::TYPE_I64
:
2051 return "TType::I64";
2052 case t_base_type::TYPE_DOUBLE
:
2053 return "TType::DOUBLE";
2055 } else if (type
->is_enum()) {
2056 return "TType::I32";
2057 } else if (type
->is_struct() || type
->is_xception()) {
2058 return "TType::STRUCT";
2059 } else if (type
->is_map()) {
2060 return "TType::MAP";
2061 } else if (type
->is_set()) {
2062 return "TType::SET";
2063 } else if (type
->is_list()) {
2064 return "TType::LST";
2067 throw "INVALID TYPE IN type_to_enum: " + type
->get_name();