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"
15 * Prepares for file generation by opening up the necessary file output
18 * @param tprogram The program to generate
20 void t_php_generator::init_generator() {
21 // Make output directory
22 MKDIR(get_out_dir().c_str());
25 string f_types_name
= get_out_dir()+program_name_
+"_types.php";
26 f_types_
.open(f_types_name
.c_str());
34 // Include other Thrift includes
35 const vector
<t_program
*>& includes
= program_
->get_includes();
36 for (size_t i
= 0; i
< includes
.size(); ++i
) {
37 string package
= includes
[i
]->get_name();
39 "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << package
<< "/" << package
<< "_types.php';" << endl
;
44 if (!program_
->get_consts().empty()) {
45 string f_consts_name
= get_out_dir()+program_name_
+"_constants.php";
46 f_consts_
.open(f_consts_name
.c_str());
50 "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" + program_name_
+ "/" + program_name_
+ "_types.php';" << endl
<<
52 "$GLOBALS['" << program_name_
<< "_CONSTANTS'] = array(); " << endl
<<
58 * Prints standard php includes
60 string
t_php_generator::php_includes() {
62 string("include_once $GLOBALS['THRIFT_ROOT'].'/Thrift.php';\n\n");
66 * Close up (or down) some filez.
68 void t_php_generator::close_generator() {
70 f_types_
<< "?>" << endl
;
73 if (!program_
->get_consts().empty()) {
74 f_consts_
<< "?>" << endl
;
80 * Generates a typedef. This is not done in PHP, types are all implicit.
82 * @param ttypedef The type definition
84 void t_php_generator::generate_typedef(t_typedef
* ttypedef
) {}
87 * Generates code for an enumerated type. Since define is expensive to lookup
88 * in PHP, we use a global array for this.
90 * @param tenum The enumeration
92 void t_php_generator::generate_enum(t_enum
* tenum
) {
94 "$GLOBALS['" << php_namespace(tenum
->get_program()) << "E_" << tenum
->get_name() << "'] = array(" << endl
;
96 vector
<t_enum_value
*> constants
= tenum
->get_constants();
97 vector
<t_enum_value
*>::iterator c_iter
;
99 for (c_iter
= constants
.begin(); c_iter
!= constants
.end(); ++c_iter
) {
100 if ((*c_iter
)->has_value()) {
101 value
= (*c_iter
)->get_value();
107 " '" << (*c_iter
)->get_name() << "' => " << value
<< "," << endl
;
111 ");" << endl
<< endl
;
114 // We're also doing it this way to see how it performs. It's more legible
115 // code but you can't do things like an 'extract' on it, which is a bit of
118 "final class " << php_namespace(tenum
->get_program()) << tenum
->get_name() << " {" << endl
;
122 for (c_iter
= constants
.begin(); c_iter
!= constants
.end(); ++c_iter
) {
123 if ((*c_iter
)->has_value()) {
124 value
= (*c_iter
)->get_value();
130 "const " << (*c_iter
)->get_name() << " = " << value
<< ";" << endl
;
134 "static public $__names = array(" << endl
;
136 for (c_iter
= constants
.begin(); c_iter
!= constants
.end(); ++c_iter
) {
137 if ((*c_iter
)->has_value()) {
138 value
= (*c_iter
)->get_value();
144 " " << value
<< " => '" << (*c_iter
)->get_name() << "'," << endl
;
150 f_types_
<< "}" << endl
<< endl
;
154 * Generate a constant value
156 void t_php_generator::generate_const(t_const
* tconst
) {
157 t_type
* type
= tconst
->get_type();
158 string name
= tconst
->get_name();
159 t_const_value
* value
= tconst
->get_value();
161 f_consts_
<< "$GLOBALS['" << program_name_
<< "_CONSTANTS']['" << name
<< "'] = ";
162 f_consts_
<< render_const_value(type
, value
);
163 f_consts_
<< ";" << endl
<< endl
;
167 * Prints the value of a constant with the given type. Note that type checking
168 * is NOT performed in this function as it is always run beforehand using the
169 * validate_types method in main.cc
171 string
t_php_generator::render_const_value(t_type
* type
, t_const_value
* value
) {
172 std::ostringstream out
;
173 type
= get_true_type(type
);
174 if (type
->is_base_type()) {
175 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
177 case t_base_type::TYPE_STRING
:
178 out
<< "'" << value
->get_string() << "'";
180 case t_base_type::TYPE_BOOL
:
181 out
<< (value
->get_integer() > 0 ? "true" : "false");
183 case t_base_type::TYPE_BYTE
:
184 case t_base_type::TYPE_I16
:
185 case t_base_type::TYPE_I32
:
186 case t_base_type::TYPE_I64
:
187 out
<< value
->get_integer();
189 case t_base_type::TYPE_DOUBLE
:
190 if (value
->get_type() == t_const_value::CV_INTEGER
) {
191 out
<< value
->get_integer();
193 out
<< value
->get_double();
197 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase
);
199 } else if (type
->is_enum()) {
200 indent(out
) << value
->get_integer();
201 } else if (type
->is_struct() || type
->is_xception()) {
202 out
<< "new " << php_namespace(type
->get_program()) << type
->get_name() << "(array(" << endl
;
204 const vector
<t_field
*>& fields
= ((t_struct
*)type
)->get_members();
205 vector
<t_field
*>::const_iterator f_iter
;
206 const map
<t_const_value
*, t_const_value
*>& val
= value
->get_map();
207 map
<t_const_value
*, t_const_value
*>::const_iterator v_iter
;
208 for (v_iter
= val
.begin(); v_iter
!= val
.end(); ++v_iter
) {
209 t_type
* field_type
= NULL
;
210 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
211 if ((*f_iter
)->get_name() == v_iter
->first
->get_string()) {
212 field_type
= (*f_iter
)->get_type();
215 if (field_type
== NULL
) {
216 throw "type error: " + type
->get_name() + " has no field " + v_iter
->first
->get_string();
219 out
<< render_const_value(g_type_string
, v_iter
->first
);
221 out
<< render_const_value(field_type
, v_iter
->second
);
226 } else if (type
->is_map()) {
227 t_type
* ktype
= ((t_map
*)type
)->get_key_type();
228 t_type
* vtype
= ((t_map
*)type
)->get_val_type();
229 out
<< "array(" << endl
;
231 const map
<t_const_value
*, t_const_value
*>& val
= value
->get_map();
232 map
<t_const_value
*, t_const_value
*>::const_iterator v_iter
;
233 for (v_iter
= val
.begin(); v_iter
!= val
.end(); ++v_iter
) {
235 out
<< render_const_value(ktype
, v_iter
->first
);
237 out
<< render_const_value(vtype
, v_iter
->second
);
242 } else if (type
->is_list() || type
->is_set()) {
244 if (type
->is_list()) {
245 etype
= ((t_list
*)type
)->get_elem_type();
247 etype
= ((t_set
*)type
)->get_elem_type();
249 out
<< "array(" << endl
;
251 const vector
<t_const_value
*>& val
= value
->get_list();
252 vector
<t_const_value
*>::const_iterator v_iter
;
253 for (v_iter
= val
.begin(); v_iter
!= val
.end(); ++v_iter
) {
255 out
<< render_const_value(etype
, *v_iter
);
256 if (type
->is_set()) {
270 void t_php_generator::generate_struct(t_struct
* tstruct
) {
271 generate_php_struct(tstruct
, false);
275 * Generates a struct definition for a thrift exception. Basically the same
276 * as a struct but extends the Exception class.
278 * @param txception The struct definition
280 void t_php_generator::generate_xception(t_struct
* txception
) {
281 generate_php_struct(txception
, true);
285 * Structs can be normal or exceptions.
287 void t_php_generator::generate_php_struct(t_struct
* tstruct
,
289 generate_php_struct_definition(f_types_
, tstruct
, is_exception
);
292 void t_php_generator::generate_php_type_spec(ofstream
& out
,
294 t
= get_true_type(t
);
295 indent(out
) << "'type' => " << type_to_enum(t
) << "," << endl
;
297 if (t
->is_base_type() || t
->is_enum()) {
298 // Noop, type is all we need
299 } else if (t
->is_struct() || t
->is_xception()) {
300 indent(out
) << "'class' => '" << php_namespace(t
->get_program()) << t
->get_name() <<"'," << endl
;
301 } else if (t
->is_map()) {
302 t_type
* ktype
= get_true_type(((t_map
*)t
)->get_key_type());
303 t_type
* vtype
= get_true_type(((t_map
*)t
)->get_val_type());
304 indent(out
) << "'ktype' => " << type_to_enum(ktype
) << "," << endl
;
305 indent(out
) << "'vtype' => " << type_to_enum(vtype
) << "," << endl
;
306 indent(out
) << "'key' => array(" << endl
;
308 generate_php_type_spec(out
, ktype
);
310 indent(out
) << ")," << endl
;
311 indent(out
) << "'val' => array(" << endl
;
313 generate_php_type_spec(out
, vtype
);
314 indent(out
) << ")," << endl
;
316 } else if (t
->is_list() || t
->is_set()) {
319 etype
= get_true_type(((t_list
*)t
)->get_elem_type());
321 etype
= get_true_type(((t_set
*)t
)->get_elem_type());
323 indent(out
) << "'etype' => " << type_to_enum(etype
) <<"," << endl
;
324 indent(out
) << "'elem' => array(" << endl
;
326 generate_php_type_spec(out
, etype
);
327 indent(out
) << ")," << endl
;
330 throw "compiler error: no type for php struct spec field";
336 * Generates the struct specification structure, which fully qualifies enough
337 * type information to generalize serialization routines.
339 void t_php_generator::generate_php_struct_spec(ofstream
& out
,
341 indent(out
) << "if (!isset(self::$_TSPEC)) {" << endl
;
344 indent(out
) << "self::$_TSPEC = array(" << endl
;
347 const vector
<t_field
*>& members
= tstruct
->get_members();
348 vector
<t_field
*>::const_iterator m_iter
;
349 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
) {
350 t_type
* t
= get_true_type((*m_iter
)->get_type());
351 indent(out
) << (*m_iter
)->get_key() << " => array(" << endl
;
354 indent() << "'var' => '" << (*m_iter
)->get_name() << "'," << endl
;
355 generate_php_type_spec(out
, t
);
356 indent(out
) << ")," << endl
;
361 indent(out
) << " );" << endl
;
363 indent(out
) << "}" << endl
;
367 void t_php_generator::generate_php_struct_definition(ofstream
& out
,
372 ofstream autoload_out
;
373 string f_struct
= program_name_
+"."+(tstruct
->get_name())+".php";
374 string f_struct_name
= get_out_dir()+f_struct
;
375 autoload_out
.open(f_struct_name
.c_str());
376 autoload_out
<< "<?php" << endl
;
377 _generate_php_struct_definition(autoload_out
, tstruct
, is_exception
);
378 autoload_out
<< endl
<< "?>" << endl
;
379 autoload_out
.close();
382 "$GLOBALS['THRIFT_AUTOLOAD']['" << lowercase(php_namespace(tstruct
->get_program()) + tstruct
->get_name()) << "'] = '" << program_name_
<< "/" << f_struct
<< "';" << endl
;
385 _generate_php_struct_definition(out
, tstruct
, is_exception
);
390 * Generates a struct definition for a thrift data type. This is nothing in PHP
391 * where the objects are all just associative arrays (unless of course we
392 * decide to start using objects for them...)
394 * @param tstruct The struct definition
396 void t_php_generator::_generate_php_struct_definition(ofstream
& out
,
399 const vector
<t_field
*>& members
= tstruct
->get_members();
400 vector
<t_field
*>::const_iterator m_iter
;
403 "class " << php_namespace(tstruct
->get_program()) << tstruct
->get_name();
405 out
<< " extends TException";
407 out
<< " extends TBase";
414 indent(out
) << "static $_TSPEC;" << endl
<< endl
;
417 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
) {
418 string dval
= "null";
419 t_type
* t
= get_true_type((*m_iter
)->get_type());
420 if ((*m_iter
)->get_value() != NULL
&& !(t
->is_struct() || t
->is_xception())) {
421 dval
= render_const_value((*m_iter
)->get_type(), (*m_iter
)->get_value());
424 "public $" << (*m_iter
)->get_name() << " = " << dval
<< ";" << endl
;
429 // Generate constructor from array
430 if (oop_
|| members
.size() > 0) {
431 string param
= (members
.size() > 0) ? "$vals=null" : "";
433 indent() << "public function __construct(" << param
<< ") {" << endl
;
437 generate_php_struct_spec(out
, tstruct
);
440 if (members
.size() > 0) {
441 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
) {
442 t_type
* t
= get_true_type((*m_iter
)->get_type());
443 if ((*m_iter
)->get_value() != NULL
&& (t
->is_struct() || t
->is_xception())) {
444 indent(out
) << "$this->" << (*m_iter
)->get_name() << " = " << render_const_value(t
, (*m_iter
)->get_value()) << ";" << endl
;
448 indent() << "if (is_array($vals)) {" << endl
;
451 out
<< indent() << "parent::construct(self::$_TSPEC, $vals);" << endl
;
453 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
) {
455 indent() << "if (isset($vals['" << (*m_iter
)->get_name() << "'])) {" << endl
<<
456 indent() << " $this->" << (*m_iter
)->get_name() << " = $vals['" << (*m_iter
)->get_name() << "'];" << endl
<<
457 indent() << "}" << endl
;
462 indent() << "}" << endl
;
469 indent() << "public function getName() {" << endl
<<
470 indent() << " return '" << tstruct
->get_name() << "';" << endl
<<
471 indent() << "}" << endl
<<
474 generate_php_struct_reader(out
, tstruct
);
475 generate_php_struct_writer(out
, tstruct
);
479 indent() << "}" << endl
<<
484 * Generates the read() method for a struct
486 void t_php_generator::generate_php_struct_reader(ofstream
& out
,
488 const vector
<t_field
*>& fields
= tstruct
->get_members();
489 vector
<t_field
*>::const_iterator f_iter
;
492 "public function read($input)" << endl
;
496 indent(out
) << "return $this->_read('" << tstruct
->get_name() << "', self::$_TSPEC, $input);" << endl
;
502 indent() << "$xfer = 0;" << endl
<<
503 indent() << "$fname = null;" << endl
<<
504 indent() << "$ftype = 0;" << endl
<<
505 indent() << "$fid = 0;" << endl
;
507 // Declare stack tmp variables
508 if (!binary_inline_
) {
510 "$xfer += $input->readStructBegin($fname);" << endl
;
513 // Loop over reading in fields
515 "while (true)" << endl
;
519 // Read beginning field marker
520 if (binary_inline_
) {
521 t_field
fftype(g_type_byte
, "ftype");
522 t_field
ffid(g_type_i16
, "fid");
523 generate_deserialize_field(out
, &fftype
);
525 indent() << "if ($ftype == TType::STOP) {" << endl
<<
526 indent() << " break;" << endl
<<
527 indent() << "}" << endl
;
528 generate_deserialize_field(out
, &ffid
);
531 "$xfer += $input->readFieldBegin($fname, $ftype, $fid);" << endl
;
532 // Check for field STOP marker and break
534 "if ($ftype == TType::STOP) {" << endl
;
543 // Switch statement on the field we are reading
545 "switch ($fid)" << endl
;
549 // Generate deserialization code for known cases
550 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
552 "case " << (*f_iter
)->get_key() << ":" << endl
;
554 indent(out
) << "if ($ftype == " << type_to_enum((*f_iter
)->get_type()) << ") {" << endl
;
556 generate_deserialize_field(out
, *f_iter
, "this->");
559 indent() << "} else {" << endl
;
560 if (binary_inline_
) {
561 indent(out
) << " $xfer += TProtocol::skipBinary($input, $ftype);" << endl
;
563 indent(out
) << " $xfer += $input->skip($ftype);" << endl
;
566 indent() << "}" << endl
<<
567 indent() << "break;" << endl
;
571 // In the default case we skip the field
572 indent(out
) << "default:" << endl
;
573 if (binary_inline_
) {
574 indent(out
) << " $xfer += TProtocol::skipBinary($input, $ftype);" << endl
;
576 indent(out
) << " $xfer += $input->skip($ftype);" << endl
;
578 indent(out
) << " break;" << endl
;
582 if (!binary_inline_
) {
583 // Read field end marker
585 "$xfer += $input->readFieldEnd();" << endl
;
590 if (!binary_inline_
) {
592 "$xfer += $input->readStructEnd();" << endl
;
596 "return $xfer;" << endl
;
600 indent() << "}" << endl
<<
605 * Generates the write() method for a struct
607 void t_php_generator::generate_php_struct_writer(ofstream
& out
,
609 string name
= tstruct
->get_name();
610 const vector
<t_field
*>& fields
= tstruct
->get_members();
611 vector
<t_field
*>::const_iterator f_iter
;
613 if (binary_inline_
) {
615 "public function write(&$output) {" << endl
;
618 "public function write($output) {" << endl
;
623 indent(out
) << "return $this->_write('" << tstruct
->get_name() << "', self::$_TSPEC, $output);" << endl
;
629 "$xfer = 0;" << endl
;
631 if (!binary_inline_
) {
633 "$xfer += $output->writeStructBegin('" << name
<< "');" << endl
;
636 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
638 indent() << "if ($this->" << (*f_iter
)->get_name() << " !== null) {" << endl
;
641 // Write field header
642 if (binary_inline_
) {
644 indent() << "$output .= pack('c', " << type_to_enum((*f_iter
)->get_type()) << ");" << endl
<<
645 indent() << "$output .= pack('n', " << (*f_iter
)->get_key() << ");" << endl
;
648 "$xfer += $output->writeFieldBegin(" <<
649 "'" << (*f_iter
)->get_name() << "', " <<
650 type_to_enum((*f_iter
)->get_type()) << ", " <<
651 (*f_iter
)->get_key() << ");" << endl
;
654 // Write field contents
655 generate_serialize_field(out
, *f_iter
, "this->");
657 // Write field closer
658 if (!binary_inline_
) {
660 "$xfer += $output->writeFieldEnd();" << endl
;
668 if (binary_inline_
) {
670 indent() << "$output .= pack('c', TType::STOP);" << endl
;
673 indent() << "$xfer += $output->writeFieldStop();" << endl
<<
674 indent() << "$xfer += $output->writeStructEnd();" << endl
;
678 indent() << "return $xfer;" << endl
;
682 indent() << "}" << endl
<<
687 * Generates a thrift service.
689 * @param tservice The service definition
691 void t_php_generator::generate_service(t_service
* tservice
) {
692 string f_service_name
= get_out_dir()+service_name_
+".php";
693 f_service_
.open(f_service_name
.c_str());
701 "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << program_name_
<< "/" << program_name_
<< "_types.php';" << endl
;
703 if (tservice
->get_extends() != NULL
) {
705 "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << tservice
->get_extends()->get_program()->get_name() << "/" << tservice
->get_extends()->get_name() << ".php';" << endl
;
711 // Generate the three main parts of the service (well, two for now in PHP)
712 generate_service_interface(tservice
);
714 generate_service_rest(tservice
);
716 generate_service_client(tservice
);
717 generate_service_helpers(tservice
);
719 generate_service_processor(tservice
);
722 // Close service file
723 f_service_
<< "?>" << endl
;
728 * Generates a service server definition.
730 * @param tservice The service to generate a server for.
732 void t_php_generator::generate_service_processor(t_service
* tservice
) {
733 // Generate the dispatch methods
734 vector
<t_function
*> functions
= tservice
->get_functions();
735 vector
<t_function
*>::iterator f_iter
;
738 string extends_processor
= "";
739 if (tservice
->get_extends() != NULL
) {
740 extends
= tservice
->get_extends()->get_name();
741 extends_processor
= " extends " + extends
+ "Processor";
744 // Generate the header portion
746 "class " << service_name_
<< "Processor" << extends_processor
<< " {" << endl
;
749 if (extends
.empty()) {
751 indent() << "protected $handler_ = null;" << endl
;
755 indent() << "public function __construct($handler) {" << endl
;
756 if (extends
.empty()) {
758 indent() << " $this->handler_ = $handler;" << endl
;
761 indent() << " parent::__construct($handler);" << endl
;
764 indent() << "}" << endl
<<
767 // Generate the server implementation
768 indent(f_service_
) <<
769 "public function process($input, $output) {" << endl
;
773 indent() << "$rseqid = 0;" << endl
<<
774 indent() << "$fname = null;" << endl
<<
775 indent() << "$mtype = 0;" << endl
<<
778 if (binary_inline_
) {
779 t_field
ffname(g_type_string
, "fname");
780 t_field
fmtype(g_type_byte
, "mtype");
781 t_field
fseqid(g_type_i32
, "rseqid");
782 generate_deserialize_field(f_service_
, &ffname
, "", true);
783 generate_deserialize_field(f_service_
, &fmtype
, "", true);
784 generate_deserialize_field(f_service_
, &fseqid
, "", true);
787 indent() << "$input->readMessageBegin($fname, $mtype, $rseqid);" << endl
;
790 // HOT: check for method implementation
792 indent() << "$methodname = 'process_'.$fname;" << endl
<<
793 indent() << "if (!method_exists($this, $methodname)) {" << endl
;
794 if (binary_inline_
) {
796 indent() << " throw new Exception('Function '.$fname.' not implemented.');" << endl
;
799 indent() << " $input->skip(TType::STRUCT);" << endl
<<
800 indent() << " $input->readMessageEnd();" << endl
<<
801 indent() << " $x = new TApplicationException('Function '.$fname.' not implemented.', TApplicationException::UNKNOWN_METHOD);" << endl
<<
802 indent() << " $output->writeMessageBegin($fname, TMessageType::EXCEPTION, $rseqid);" << endl
<<
803 indent() << " $x->write($output);" << endl
<<
804 indent() << " $output->writeMessageEnd();" << endl
<<
805 indent() << " $output->getTransport()->flush();" << endl
<<
806 indent() << " return;" << endl
;
809 indent() << "}" << endl
<<
810 indent() << "$this->$methodname($rseqid, $input, $output);" << endl
<<
811 indent() << "return true;" << endl
;
814 indent() << "}" << endl
<<
817 // Generate the process subfunctions
818 for (f_iter
= functions
.begin(); f_iter
!= functions
.end(); ++f_iter
) {
819 generate_process_function(tservice
, *f_iter
);
823 f_service_
<< "}" << endl
;
827 * Generates a process function definition.
829 * @param tfunction The function to write a dispatcher for
831 void t_php_generator::generate_process_function(t_service
* tservice
,
832 t_function
* tfunction
) {
834 indent(f_service_
) <<
835 "protected function process_" << tfunction
->get_name() <<
836 "($seqid, $input, $output) {" << endl
;
839 string argsname
= php_namespace(tservice
->get_program()) + service_name_
+ "_" + tfunction
->get_name() + "_args";
840 string resultname
= php_namespace(tservice
->get_program()) + service_name_
+ "_" + tfunction
->get_name() + "_result";
843 indent() << "$args = new " << argsname
<< "();" << endl
<<
844 indent() << "$args->read($input);" << endl
;
845 if (!binary_inline_
) {
847 indent() << "$input->readMessageEnd();" << endl
;
850 t_struct
* xs
= tfunction
->get_xceptions();
851 const std::vector
<t_field
*>& xceptions
= xs
->get_members();
852 vector
<t_field
*>::const_iterator x_iter
;
854 // Declare result for non async function
855 if (!tfunction
->is_async()) {
857 indent() << "$result = new " << resultname
<< "();" << endl
;
860 // Try block for a function with exceptions
861 if (xceptions
.size() > 0) {
863 indent() << "try {" << endl
;
867 // Generate the function call
868 t_struct
* arg_struct
= tfunction
->get_arglist();
869 const std::vector
<t_field
*>& fields
= arg_struct
->get_members();
870 vector
<t_field
*>::const_iterator f_iter
;
872 f_service_
<< indent();
873 if (!tfunction
->is_async() && !tfunction
->get_returntype()->is_void()) {
874 f_service_
<< "$result->success = ";
877 "$this->handler_->" << tfunction
->get_name() << "(";
879 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
885 f_service_
<< "$args->" << (*f_iter
)->get_name();
887 f_service_
<< ");" << endl
;
889 if (!tfunction
->is_async() && xceptions
.size() > 0) {
891 for (x_iter
= xceptions
.begin(); x_iter
!= xceptions
.end(); ++x_iter
) {
893 indent() << "} catch (" << php_namespace((*x_iter
)->get_type()->get_program()) << (*x_iter
)->get_type()->get_name() << " $" << (*x_iter
)->get_name() << ") {" << endl
;
894 if (!tfunction
->is_async()) {
897 indent() << "$result->" << (*x_iter
)->get_name() << " = $" << (*x_iter
)->get_name() << ";" << endl
;
899 f_service_
<< indent();
902 f_service_
<< "}" << endl
;
905 // Shortcut out here for async functions
906 if (tfunction
->is_async()) {
908 indent() << "return;" << endl
;
911 indent() << "}" << endl
;
915 // Serialize the request header
916 if (binary_inline_
) {
918 indent() << "$buff = pack('N', (0x80010000 | TMessageType::REPLY)); " << endl
<<
919 indent() << "$buff .= pack('N', strlen('" << tfunction
->get_name() << "'));" << endl
<<
920 indent() << "$buff .= '" << tfunction
->get_name() << "';" << endl
<<
921 indent() << "$buff .= pack('N', $seqid);" << endl
<<
922 indent() << "$result->write($buff);" << endl
<<
923 indent() << "$output->write($buff);" << endl
<<
924 indent() << "$output->flush();" << endl
;
927 indent() << "$output->writeMessageBegin('" << tfunction
->get_name() << "', TMessageType::REPLY, $seqid);" << endl
<<
928 indent() << "$result->write($output);" << endl
<<
929 indent() << "$output->getTransport()->flush();" << endl
;
935 indent() << "}" << endl
;
939 * Generates helper functions for a service.
941 * @param tservice The service to generate a header definition for
943 void t_php_generator::generate_service_helpers(t_service
* tservice
) {
944 vector
<t_function
*> functions
= tservice
->get_functions();
945 vector
<t_function
*>::iterator f_iter
;
948 "// HELPER FUNCTIONS AND STRUCTURES" << endl
<< endl
;
950 for (f_iter
= functions
.begin(); f_iter
!= functions
.end(); ++f_iter
) {
951 t_struct
* ts
= (*f_iter
)->get_arglist();
952 string name
= ts
->get_name();
953 ts
->set_name(service_name_
+ "_" + name
);
954 generate_php_struct_definition(f_service_
, ts
, false);
955 generate_php_function_helpers(*f_iter
);
961 * Generates a struct and helpers for a function.
963 * @param tfunction The function
965 void t_php_generator::generate_php_function_helpers(t_function
* tfunction
) {
966 if (!tfunction
->is_async()) {
967 t_struct
result(program_
, service_name_
+ "_" + tfunction
->get_name() + "_result");
968 t_field
success(tfunction
->get_returntype(), "success", 0);
969 if (!tfunction
->get_returntype()->is_void()) {
970 result
.append(&success
);
973 t_struct
* xs
= tfunction
->get_xceptions();
974 const vector
<t_field
*>& fields
= xs
->get_members();
975 vector
<t_field
*>::const_iterator f_iter
;
976 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
977 result
.append(*f_iter
);
980 generate_php_struct_definition(f_service_
, &result
, false);
985 * Generates a service interface definition.
987 * @param tservice The service to generate a header definition for
989 void t_php_generator::generate_service_interface(t_service
* tservice
) {
991 string extends_if
= "";
992 if (tservice
->get_extends() != NULL
) {
993 extends
= " extends " + tservice
->get_extends()->get_name();
994 extends_if
= " extends " + tservice
->get_extends()->get_name() + "If";
997 "interface " << service_name_
<< "If" << extends_if
<< " {" << endl
;
999 vector
<t_function
*> functions
= tservice
->get_functions();
1000 vector
<t_function
*>::iterator f_iter
;
1001 for (f_iter
= functions
.begin(); f_iter
!= functions
.end(); ++f_iter
) {
1002 indent(f_service_
) <<
1003 "public function " << function_signature(*f_iter
) << ";" << endl
;
1007 "}" << endl
<< endl
;
1011 * Generates a REST interface
1013 void t_php_generator::generate_service_rest(t_service
* tservice
) {
1014 string extends
= "";
1015 string extends_if
= "";
1016 if (tservice
->get_extends() != NULL
) {
1017 extends
= " extends " + tservice
->get_extends()->get_name();
1018 extends_if
= " extends " + tservice
->get_extends()->get_name() + "Rest";
1021 "class " << service_name_
<< "Rest" << extends_if
<< " {" << endl
;
1024 if (extends
.empty()) {
1026 indent() << "protected $impl_;" << endl
<<
1031 indent() << "public function __construct($impl) {" << endl
<<
1032 indent() << " $this->impl_ = $impl;" << endl
<<
1033 indent() << "}" << endl
<<
1036 vector
<t_function
*> functions
= tservice
->get_functions();
1037 vector
<t_function
*>::iterator f_iter
;
1038 for (f_iter
= functions
.begin(); f_iter
!= functions
.end(); ++f_iter
) {
1039 indent(f_service_
) <<
1040 "public function " << (*f_iter
)->get_name() << "($request) {" << endl
;
1042 const vector
<t_field
*>& args
= (*f_iter
)->get_arglist()->get_members();
1043 vector
<t_field
*>::const_iterator a_iter
;
1044 for (a_iter
= args
.begin(); a_iter
!= args
.end(); ++a_iter
) {
1045 t_type
* atype
= get_true_type((*a_iter
)->get_type());
1046 string cast
= type_to_cast(atype
);
1047 string req
= "$request['" + (*a_iter
)->get_name() + "']";
1048 if (atype
->is_bool()) {
1050 indent() << "$" << (*a_iter
)->get_name() << " = " << cast
<< "(!empty(" << req
<< ") && (" << req
<< " !== 'false'));" << endl
;
1053 indent() << "$" << (*a_iter
)->get_name() << " = isset(" << req
<< ") ? " << cast
<< req
<< " : null;" << endl
;
1055 if (atype
->is_string() &&
1056 ((t_base_type
*)atype
)->is_string_list()) {
1058 indent() << "$" << (*a_iter
)->get_name() << " = explode(',', $" << (*a_iter
)->get_name() << ");" << endl
;
1059 } else if (atype
->is_map() || atype
->is_list()) {
1061 indent() << "$" << (*a_iter
)->get_name() << " = json_decode($" << (*a_iter
)->get_name() << ", true);" << endl
;
1062 } else if (atype
->is_set()) {
1064 indent() << "$" << (*a_iter
)->get_name() << " = array_fill_keys(json_decode($" << (*a_iter
)->get_name() << ", true), 1);" << endl
;
1065 } else if (atype
->is_struct() || atype
->is_xception()) {
1067 indent() << "$" << (*a_iter
)->get_name() << " = new " << php_namespace(atype
->get_program()) << atype
->get_name() << "(json_decode($" << (*a_iter
)->get_name() << ", true));" << endl
;
1071 indent() << "return $this->impl_->" << (*f_iter
)->get_name() << "(" << argument_list((*f_iter
)->get_arglist()) << ");" << endl
;
1073 indent(f_service_
) <<
1079 "}" << endl
<< endl
;
1082 void t_php_generator::generate_service_client(t_service
* tservice
) {
1085 ofstream autoload_out
;
1086 string f_struct
= program_name_
+"."+(tservice
->get_name())+".client.php";
1087 string f_struct_name
= get_out_dir()+f_struct
;
1088 autoload_out
.open(f_struct_name
.c_str());
1089 autoload_out
<< "<?php" << endl
;
1090 _generate_service_client(autoload_out
, tservice
);
1091 autoload_out
<< endl
<< "?>" << endl
;
1092 autoload_out
.close();
1095 "$GLOBALS['THRIFT_AUTOLOAD']['" << lowercase(service_name_
+ "Client") << "'] = '" << program_name_
<< "/" << f_struct
<< "';" << endl
;
1098 _generate_service_client(f_service_
, tservice
);
1103 * Generates a service client definition.
1105 * @param tservice The service to generate a server for.
1107 void t_php_generator::_generate_service_client(ofstream
& out
, t_service
* tservice
) {
1108 string extends
= "";
1109 string extends_client
= "";
1110 if (tservice
->get_extends() != NULL
) {
1111 extends
= tservice
->get_extends()->get_name();
1112 extends_client
= " extends " + extends
+ "Client";
1116 "class " << service_name_
<< "Client" << extends_client
<< " implements " << service_name_
<< "If {" << endl
;
1120 if (extends
.empty()) {
1122 indent() << "protected $input_ = null;" << endl
<<
1123 indent() << "protected $output_ = null;" << endl
<<
1126 indent() << "protected $seqid_ = 0;" << endl
<<
1130 // Constructor function
1132 indent() << "public function __construct($input, $output=null) {" << endl
;
1133 if (!extends
.empty()) {
1135 indent() << " parent::__construct($input, $output);" << endl
;
1138 indent() << " $this->input_ = $input;" << endl
<<
1139 indent() << " $this->output_ = $output ? $output : $input;" << endl
;
1142 indent() << "}" << endl
<< endl
;
1144 // Generate client method implementations
1145 vector
<t_function
*> functions
= tservice
->get_functions();
1146 vector
<t_function
*>::const_iterator f_iter
;
1147 for (f_iter
= functions
.begin(); f_iter
!= functions
.end(); ++f_iter
) {
1148 t_struct
* arg_struct
= (*f_iter
)->get_arglist();
1149 const vector
<t_field
*>& fields
= arg_struct
->get_members();
1150 vector
<t_field
*>::const_iterator fld_iter
;
1151 string funname
= (*f_iter
)->get_name();
1155 "public function " << function_signature(*f_iter
) << endl
;
1158 "$this->send_" << funname
<< "(";
1161 for (fld_iter
= fields
.begin(); fld_iter
!= fields
.end(); ++fld_iter
) {
1167 out
<< "$" << (*fld_iter
)->get_name();
1169 out
<< ");" << endl
;
1171 if (!(*f_iter
)->is_async()) {
1173 if (!(*f_iter
)->get_returntype()->is_void()) {
1177 "$this->recv_" << funname
<< "();" << endl
;
1183 "public function send_" << function_signature(*f_iter
) << endl
;
1186 std::string argsname
= php_namespace(tservice
->get_program()) + service_name_
+ "_" + (*f_iter
)->get_name() + "_args";
1188 // Serialize the request header
1189 if (binary_inline_
) {
1191 indent() << "$buff = pack('N', (0x80010000 | TMessageType::CALL));" << endl
<<
1192 indent() << "$buff .= pack('N', strlen('" << funname
<< "'));" << endl
<<
1193 indent() << "$buff .= '" << funname
<< "';" << endl
<<
1194 indent() << "$buff .= pack('N', $this->seqid_);" << endl
;
1197 indent() << "$this->output_->writeMessageBegin('" << (*f_iter
)->get_name() << "', TMessageType::CALL, $this->seqid_);" << endl
;
1201 indent() << "$args = new " << argsname
<< "();" << endl
;
1203 for (fld_iter
= fields
.begin(); fld_iter
!= fields
.end(); ++fld_iter
) {
1205 indent() << "$args->" << (*fld_iter
)->get_name() << " = $" << (*fld_iter
)->get_name() << ";" << endl
;
1208 // Write to the stream
1209 if (binary_inline_
) {
1211 indent() << "$args->write($buff);" << endl
<<
1212 indent() << "$this->output_->write($buff);" << endl
<<
1213 indent() << "$this->output_->flush();" << endl
;
1216 indent() << "$args->write($this->output_);" << endl
<<
1217 indent() << "$this->output_->writeMessageEnd();" << endl
<<
1218 indent() << "$this->output_->getTransport()->flush();" << endl
;
1224 if (!(*f_iter
)->is_async()) {
1225 std::string resultname
= php_namespace(tservice
->get_program()) + service_name_
+ "_" + (*f_iter
)->get_name() + "_result";
1226 t_struct
noargs(program_
);
1228 t_function
recv_function((*f_iter
)->get_returntype(),
1229 string("recv_") + (*f_iter
)->get_name(),
1234 indent() << "public function " << function_signature(&recv_function
) << endl
;
1238 indent() << "$rseqid = 0;" << endl
<<
1239 indent() << "$fname = null;" << endl
<<
1240 indent() << "$mtype = 0;" << endl
<<
1243 if (binary_inline_
) {
1244 t_field
ffname(g_type_string
, "fname");
1245 t_field
fseqid(g_type_i32
, "rseqid");
1247 indent() << "$ver = unpack('N', $this->input_->readAll(4));" << endl
<<
1248 indent() << "$ver = $ver[1];" << endl
<<
1249 indent() << "$mtype = $ver & 0xff;" << endl
<<
1250 indent() << "$ver = $ver & 0xffff0000;" << endl
<<
1251 indent() << "if ($ver != 0x80010000) throw new TProtocolException('Bad version identifier: '.$ver, TProtocolException::BAD_VERSION);" << endl
;
1252 generate_deserialize_field(out
, &ffname
, "", true);
1253 generate_deserialize_field(out
, &fseqid
, "", true);
1256 indent() << "$this->input_->readMessageBegin($fname, $mtype, $rseqid);" << endl
<<
1257 indent() << "if ($mtype == TMessageType::EXCEPTION) {" << endl
<<
1258 indent() << " $x = new TApplicationException();" << endl
<<
1259 indent() << " $x->read($this->input_);" << endl
<<
1260 indent() << " $this->input_->readMessageEnd();" << endl
<<
1261 indent() << " throw $x;" << endl
<<
1262 indent() << "}" << endl
;
1266 indent() << "$result = new " << resultname
<< "();" << endl
<<
1267 indent() << "$result->read($this->input_);" << endl
;
1269 if (!binary_inline_
) {
1271 indent() << "$this->input_->readMessageEnd();" << endl
<<
1275 // Careful, only return result if not a void function
1276 if (!(*f_iter
)->get_returntype()->is_void()) {
1278 indent() << "if ($result->success !== null) {" << endl
<<
1279 indent() << " return $result->success;" << endl
<<
1280 indent() << "}" << endl
;
1283 t_struct
* xs
= (*f_iter
)->get_xceptions();
1284 const std::vector
<t_field
*>& xceptions
= xs
->get_members();
1285 vector
<t_field
*>::const_iterator x_iter
;
1286 for (x_iter
= xceptions
.begin(); x_iter
!= xceptions
.end(); ++x_iter
) {
1288 indent() << "if ($result->" << (*x_iter
)->get_name() << " !== null) {" << endl
<<
1289 indent() << " throw $result->" << (*x_iter
)->get_name() << ";" << endl
<<
1290 indent() << "}" << endl
;
1293 // Careful, only return _result if not a void function
1294 if ((*f_iter
)->get_returntype()->is_void()) {
1299 indent() << "throw new Exception(\"" << (*f_iter
)->get_name() << " failed: unknown result\");" << endl
;
1311 "}" << endl
<< endl
;
1315 * Deserializes a field of any type.
1317 void t_php_generator::generate_deserialize_field(ofstream
&out
,
1321 t_type
* type
= get_true_type(tfield
->get_type());
1323 if (type
->is_void()) {
1324 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
1325 prefix
+ tfield
->get_name();
1328 string name
= prefix
+ tfield
->get_name();
1330 if (type
->is_struct() || type
->is_xception()) {
1331 generate_deserialize_struct(out
,
1336 if (type
->is_container()) {
1337 generate_deserialize_container(out
, type
, name
);
1338 } else if (type
->is_base_type() || type
->is_enum()) {
1340 out
<< indent() << "if (($input instanceof TProtocol::$TBINARYPROTOCOLACCELERATED) && function_exists('thrift_protocol_binary_deserialize')) {" << endl
;
1343 if (type
->is_enum()) {
1346 ttype_name
= t_base_type::t_base_name(static_cast<t_base_type
*>(type
)->get_base());
1347 for (size_t _s
= 0; _s
< ttype_name
.size(); ++_s
) {
1348 ttype_name
[_s
] = toupper(ttype_name
[_s
]);
1352 out
<< indent() << "$" << name
<< " = thrift_protocol_binary_deserialize(TType::" << ttype_name
<< ", $input);" << endl
;
1354 out
<< indent() << "} else {" << endl
;
1358 if (binary_inline_
) {
1359 std::string itrans
= (inclass
? "$this->input_" : "$input");
1361 if (type
->is_base_type()) {
1362 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
1364 case t_base_type::TYPE_VOID
:
1365 throw "compiler error: cannot serialize void field in a struct: " +
1368 case t_base_type::TYPE_STRING
:
1370 indent() << "$len = unpack('N', " << itrans
<< "->readAll(4));" << endl
<<
1371 indent() << "$len = $len[1];" << endl
<<
1372 indent() << "if ($len > 0x7fffffff) {" << endl
<<
1373 indent() << " $len = 0 - (($len - 1) ^ 0xffffffff);" << endl
<<
1374 indent() << "}" << endl
<<
1375 indent() << "$" << name
<< " = " << itrans
<< "->readAll($len);" << endl
;
1377 case t_base_type::TYPE_BOOL
:
1379 indent() << "$" << name
<< " = unpack('c', " << itrans
<< "->readAll(1));" << endl
<<
1380 indent() << "$" << name
<< " = (bool)$" << name
<< "[1];" << endl
;
1382 case t_base_type::TYPE_BYTE
:
1384 indent() << "$" << name
<< " = unpack('c', " << itrans
<< "->readAll(1));" << endl
<<
1385 indent() << "$" << name
<< " = $" << name
<< "[1];" << endl
;
1387 case t_base_type::TYPE_I16
:
1389 indent() << "$val = unpack('n', " << itrans
<< "->readAll(2));" << endl
<<
1390 indent() << "$val = $val[1];" << endl
<<
1391 indent() << "if ($val > 0x7fff) {" << endl
<<
1392 indent() << " $val = 0 - (($val - 1) ^ 0xffff);" << endl
<<
1393 indent() << "}" << endl
<<
1394 indent() << "$" << name
<< " = $val;" << endl
;
1396 case t_base_type::TYPE_I32
:
1398 indent() << "$val = unpack('N', " << itrans
<< "->readAll(4));" << endl
<<
1399 indent() << "$val = $val[1];" << endl
<<
1400 indent() << "if ($val > 0x7fffffff) {" << endl
<<
1401 indent() << " $val = 0 - (($val - 1) ^ 0xffffffff);" << endl
<<
1402 indent() << "}" << endl
<<
1403 indent() << "$" << name
<< " = $val;" << endl
;
1405 case t_base_type::TYPE_I64
:
1407 indent() << "$arr = unpack('N2', " << itrans
<< "->readAll(8));" << endl
<<
1408 indent() << "if ($arr[1] & 0x80000000) {" << endl
<<
1409 indent() << " $arr[1] = $arr[1] ^ 0xFFFFFFFF;" << endl
<<
1410 indent() << " $arr[2] = $arr[2] ^ 0xFFFFFFFF;" << endl
<<
1411 indent() << " $" << name
<< " = 0 - $arr[1]*4294967296 - $arr[2] - 1;" << endl
<<
1412 indent() << "} else {" << endl
<<
1413 indent() << " $" << name
<< " = $arr[1]*4294967296 + $arr[2];" << endl
<<
1414 indent() << "}" << endl
;
1416 case t_base_type::TYPE_DOUBLE
:
1418 indent() << "$arr = unpack('d', strrev(" << itrans
<< "->readAll(8)));" << endl
<<
1419 indent() << "$" << name
<< " = $arr[1];" << endl
;
1422 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase
) + tfield
->get_name();
1424 } else if (type
->is_enum()) {
1426 indent() << "$val = unpack('N', " << itrans
<< "->readAll(4));" << endl
<<
1427 indent() << "$val = $val[1];" << endl
<<
1428 indent() << "if ($val > 0x7fffffff) {" << endl
<<
1429 indent() << " $val = 0 - (($val - 1) ^ 0xffffffff);" << endl
<<
1430 indent() << "}" << endl
<<
1431 indent() << "$" << name
<< " = $val;" << endl
;
1436 "$xfer += $input->";
1438 if (type
->is_base_type()) {
1439 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
1441 case t_base_type::TYPE_VOID
:
1442 throw "compiler error: cannot serialize void field in a struct: " +
1445 case t_base_type::TYPE_STRING
:
1446 out
<< "readString($" << name
<< ");";
1448 case t_base_type::TYPE_BOOL
:
1449 out
<< "readBool($" << name
<< ");";
1451 case t_base_type::TYPE_BYTE
:
1452 out
<< "readByte($" << name
<< ");";
1454 case t_base_type::TYPE_I16
:
1455 out
<< "readI16($" << name
<< ");";
1457 case t_base_type::TYPE_I32
:
1458 out
<< "readI32($" << name
<< ");";
1460 case t_base_type::TYPE_I64
:
1461 out
<< "readI64($" << name
<< ");";
1463 case t_base_type::TYPE_DOUBLE
:
1464 out
<< "readDouble($" << name
<< ");";
1467 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase
);
1469 } else if (type
->is_enum()) {
1470 out
<< "readI32($" << name
<< ");";
1474 out
<< indent() << "}" << endl
;
1477 printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
1478 tfield
->get_name().c_str(), type
->get_name().c_str());
1484 * Generates an unserializer for a variable. This makes two key assumptions,
1485 * first that there is a const char* variable named data that points to the
1486 * buffer for deserialization, and that there is a variable protocol which
1487 * is a reference to a TProtocol serialization object.
1489 void t_php_generator::generate_deserialize_struct(ofstream
&out
,
1493 indent() << "$" << prefix
<< " = new " << php_namespace(tstruct
->get_program()) << tstruct
->get_name() << "();" << endl
<<
1494 indent() << "$xfer += $" << prefix
<< "->read($input);" << endl
;
1497 void t_php_generator::generate_deserialize_container(ofstream
&out
,
1500 out
<< indent() << "if (($input instanceof TProtocol::$TBINARYPROTOCOLACCELERATED) && function_exists('thrift_protocol_binary_deserialize'))" << endl
;
1504 t_type
* tvaluetype
= NULL
;
1505 if (ttype
->is_map()) {
1507 tvaluetype
= reinterpret_cast<t_map
*>(ttype
)->get_val_type();
1508 } else if (ttype
->is_set()) {
1510 tvaluetype
= reinterpret_cast<t_set
*>(ttype
)->get_elem_type();
1511 } else if (ttype
->is_list()) {
1513 tvaluetype
= reinterpret_cast<t_list
*>(ttype
)->get_elem_type();
1515 if (tvaluetype
->is_struct()) {
1516 out
<< indent() << "$" << prefix
<< " = thrift_protocol_binary_deserialize(TType::" << ttype_name
<< ", $input, '" << tvaluetype
->get_name() << "');" << endl
;
1518 out
<< indent() << "$" << prefix
<< " = thrift_protocol_binary_deserialize(TType::" << ttype_name
<< ", $input);" << endl
;
1521 out
<< indent() << "else" << endl
;
1524 string size
= tmp("_size");
1525 string ktype
= tmp("_ktype");
1526 string vtype
= tmp("_vtype");
1527 string etype
= tmp("_etype");
1529 t_field
fsize(g_type_i32
, size
);
1530 t_field
fktype(g_type_byte
, ktype
);
1531 t_field
fvtype(g_type_byte
, vtype
);
1532 t_field
fetype(g_type_byte
, etype
);
1535 indent() << "$" << prefix
<< " = array();" << endl
<<
1536 indent() << "$" << size
<< " = 0;" << endl
;
1538 // Declare variables, read header
1539 if (ttype
->is_map()) {
1541 indent() << "$" << ktype
<< " = 0;" << endl
<<
1542 indent() << "$" << vtype
<< " = 0;" << endl
;
1543 if (binary_inline_
) {
1544 generate_deserialize_field(out
, &fktype
);
1545 generate_deserialize_field(out
, &fvtype
);
1546 generate_deserialize_field(out
, &fsize
);
1549 indent() << "$xfer += $input->readMapBegin(" <<
1550 "$" << ktype
<< ", $" << vtype
<< ", $" << size
<< ");" << endl
;
1552 } else if (ttype
->is_set()) {
1553 if (binary_inline_
) {
1554 generate_deserialize_field(out
, &fetype
);
1555 generate_deserialize_field(out
, &fsize
);
1558 indent() << "$" << etype
<< " = 0;" << endl
<<
1559 indent() << "$xfer += $input->readSetBegin(" <<
1560 "$" << etype
<< ", $" << size
<< ");" << endl
;
1562 } else if (ttype
->is_list()) {
1563 if (binary_inline_
) {
1564 generate_deserialize_field(out
, &fetype
);
1565 generate_deserialize_field(out
, &fsize
);
1568 indent() << "$" << etype
<< " = 0;" << endl
<<
1569 indent() << "$xfer += $input->readListBegin(" <<
1570 "$" << etype
<< ", $" << size
<< ");" << endl
;
1574 // For loop iterates over elements
1575 string i
= tmp("_i");
1578 i
<< " = 0; $" << i
<< " < $" << size
<< "; ++$" << i
<< ")" << endl
;
1582 if (ttype
->is_map()) {
1583 generate_deserialize_map_element(out
, (t_map
*)ttype
, prefix
);
1584 } else if (ttype
->is_set()) {
1585 generate_deserialize_set_element(out
, (t_set
*)ttype
, prefix
);
1586 } else if (ttype
->is_list()) {
1587 generate_deserialize_list_element(out
, (t_list
*)ttype
, prefix
);
1592 if (!binary_inline_
) {
1593 // Read container end
1594 if (ttype
->is_map()) {
1595 indent(out
) << "$xfer += $input->readMapEnd();" << endl
;
1596 } else if (ttype
->is_set()) {
1597 indent(out
) << "$xfer += $input->readSetEnd();" << endl
;
1598 } else if (ttype
->is_list()) {
1599 indent(out
) << "$xfer += $input->readListEnd();" << endl
;
1608 * Generates code to deserialize a map
1610 void t_php_generator::generate_deserialize_map_element(ofstream
&out
,
1613 string key
= tmp("key");
1614 string val
= tmp("val");
1615 t_field
fkey(tmap
->get_key_type(), key
);
1616 t_field
fval(tmap
->get_val_type(), val
);
1619 declare_field(&fkey
, true, true) << endl
;
1621 declare_field(&fval
, true, true) << endl
;
1623 generate_deserialize_field(out
, &fkey
);
1624 generate_deserialize_field(out
, &fval
);
1627 "$" << prefix
<< "[$" << key
<< "] = $" << val
<< ";" << endl
;
1630 void t_php_generator::generate_deserialize_set_element(ofstream
&out
,
1633 string elem
= tmp("elem");
1634 t_field
felem(tset
->get_elem_type(), elem
);
1637 "$" << elem
<< " = null;" << endl
;
1639 generate_deserialize_field(out
, &felem
);
1642 "$" << prefix
<< "[$" << elem
<< "] = true;" << endl
;
1645 void t_php_generator::generate_deserialize_list_element(ofstream
&out
,
1648 string elem
= tmp("elem");
1649 t_field
felem(tlist
->get_elem_type(), elem
);
1652 "$" << elem
<< " = null;" << endl
;
1654 generate_deserialize_field(out
, &felem
);
1657 "$" << prefix
<< " []= $" << elem
<< ";" << endl
;
1662 * Serializes a field of any type.
1664 * @param tfield The field to serialize
1665 * @param prefix Name to prepend to field name
1667 void t_php_generator::generate_serialize_field(ofstream
&out
,
1670 t_type
* type
= get_true_type(tfield
->get_type());
1672 // Do nothing for void types
1673 if (type
->is_void()) {
1674 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
1675 prefix
+ tfield
->get_name();
1678 if (type
->is_struct() || type
->is_xception()) {
1679 generate_serialize_struct(out
,
1681 prefix
+ tfield
->get_name());
1682 } else if (type
->is_container()) {
1683 generate_serialize_container(out
,
1685 prefix
+ tfield
->get_name());
1686 } else if (type
->is_base_type() || type
->is_enum()) {
1688 string name
= prefix
+ tfield
->get_name();
1690 if (binary_inline_
) {
1691 if (type
->is_base_type()) {
1692 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
1694 case t_base_type::TYPE_VOID
:
1696 "compiler error: cannot serialize void field in a struct: " + name
;
1698 case t_base_type::TYPE_STRING
:
1700 indent() << "$output .= pack('N', strlen($" << name
<< "));" << endl
<<
1701 indent() << "$output .= $" << name
<< ";" << endl
;
1703 case t_base_type::TYPE_BOOL
:
1705 indent() << "$output .= pack('c', $" << name
<< " ? 1 : 0);" << endl
;
1707 case t_base_type::TYPE_BYTE
:
1709 indent() << "$output .= pack('c', $" << name
<< ");" << endl
;
1711 case t_base_type::TYPE_I16
:
1713 indent() << "$output .= pack('n', $" << name
<< ");" << endl
;
1715 case t_base_type::TYPE_I32
:
1717 indent() << "$output .= pack('N', $" << name
<< ");" << endl
;
1719 case t_base_type::TYPE_I64
:
1721 indent() << "$output .= pack('N2', $" << name
<< " >> 32, $" << name
<< " & 0xFFFFFFFF);" << endl
;
1723 case t_base_type::TYPE_DOUBLE
:
1725 indent() << "$output .= strrev(pack('d', $" << name
<< "));" << endl
;
1728 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase
);
1730 } else if (type
->is_enum()) {
1732 indent() << "$output .= pack('N', $" << name
<< ");" << endl
;
1737 "$xfer += $output->";
1739 if (type
->is_base_type()) {
1740 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
1742 case t_base_type::TYPE_VOID
:
1744 "compiler error: cannot serialize void field in a struct: " + name
;
1746 case t_base_type::TYPE_STRING
:
1747 out
<< "writeString($" << name
<< ");";
1749 case t_base_type::TYPE_BOOL
:
1750 out
<< "writeBool($" << name
<< ");";
1752 case t_base_type::TYPE_BYTE
:
1753 out
<< "writeByte($" << name
<< ");";
1755 case t_base_type::TYPE_I16
:
1756 out
<< "writeI16($" << name
<< ");";
1758 case t_base_type::TYPE_I32
:
1759 out
<< "writeI32($" << name
<< ");";
1761 case t_base_type::TYPE_I64
:
1762 out
<< "writeI64($" << name
<< ");";
1764 case t_base_type::TYPE_DOUBLE
:
1765 out
<< "writeDouble($" << name
<< ");";
1768 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase
);
1770 } else if (type
->is_enum()) {
1771 out
<< "writeI32($" << name
<< ");";
1776 printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
1778 tfield
->get_name().c_str(),
1779 type
->get_name().c_str());
1784 * Serializes all the members of a struct.
1786 * @param tstruct The struct to serialize
1787 * @param prefix String prefix to attach to all fields
1789 void t_php_generator::generate_serialize_struct(ofstream
&out
,
1793 "$xfer += $" << prefix
<< "->write($output);" << endl
;
1797 * Writes out a container
1799 void t_php_generator::generate_serialize_container(ofstream
&out
,
1804 if (ttype
->is_map()) {
1805 if (binary_inline_
) {
1807 indent() << "$output .= pack('c', " << type_to_enum(((t_map
*)ttype
)->get_key_type()) << ");" << endl
<<
1808 indent() << "$output .= pack('c', " << type_to_enum(((t_map
*)ttype
)->get_val_type()) << ");" << endl
<<
1809 indent() << "$output .= strrev(pack('l', count($" << prefix
<< ")));" << endl
;
1812 "$output->writeMapBegin(" <<
1813 type_to_enum(((t_map
*)ttype
)->get_key_type()) << ", " <<
1814 type_to_enum(((t_map
*)ttype
)->get_val_type()) << ", " <<
1815 "count($" << prefix
<< "));" << endl
;
1817 } else if (ttype
->is_set()) {
1818 if (binary_inline_
) {
1820 indent() << "$output .= pack('c', " << type_to_enum(((t_set
*)ttype
)->get_elem_type()) << ");" << endl
<<
1821 indent() << "$output .= strrev(pack('l', count($" << prefix
<< ")));" << endl
;
1825 "$output->writeSetBegin(" <<
1826 type_to_enum(((t_set
*)ttype
)->get_elem_type()) << ", " <<
1827 "count($" << prefix
<< "));" << endl
;
1829 } else if (ttype
->is_list()) {
1830 if (binary_inline_
) {
1832 indent() << "$output .= pack('c', " << type_to_enum(((t_list
*)ttype
)->get_elem_type()) << ");" << endl
<<
1833 indent() << "$output .= strrev(pack('l', count($" << prefix
<< ")));" << endl
;
1837 "$output->writeListBegin(" <<
1838 type_to_enum(((t_list
*)ttype
)->get_elem_type()) << ", " <<
1839 "count($" << prefix
<< "));" << endl
;
1845 if (ttype
->is_map()) {
1846 string kiter
= tmp("kiter");
1847 string viter
= tmp("viter");
1849 "foreach ($" << prefix
<< " as " <<
1850 "$" << kiter
<< " => $" << viter
<< ")" << endl
;
1852 generate_serialize_map_element(out
, (t_map
*)ttype
, kiter
, viter
);
1854 } else if (ttype
->is_set()) {
1855 string iter
= tmp("iter");
1857 "foreach ($" << prefix
<< " as $" << iter
<< " => $true)" << endl
;
1859 generate_serialize_set_element(out
, (t_set
*)ttype
, iter
);
1861 } else if (ttype
->is_list()) {
1862 string iter
= tmp("iter");
1864 "foreach ($" << prefix
<< " as $" << iter
<< ")" << endl
;
1866 generate_serialize_list_element(out
, (t_list
*)ttype
, iter
);
1872 if (!binary_inline_
) {
1873 if (ttype
->is_map()) {
1875 "$output->writeMapEnd();" << endl
;
1876 } else if (ttype
->is_set()) {
1878 "$output->writeSetEnd();" << endl
;
1879 } else if (ttype
->is_list()) {
1881 "$output->writeListEnd();" << endl
;
1889 * Serializes the members of a map.
1892 void t_php_generator::generate_serialize_map_element(ofstream
&out
,
1896 t_field
kfield(tmap
->get_key_type(), kiter
);
1897 generate_serialize_field(out
, &kfield
, "");
1899 t_field
vfield(tmap
->get_val_type(), viter
);
1900 generate_serialize_field(out
, &vfield
, "");
1904 * Serializes the members of a set.
1906 void t_php_generator::generate_serialize_set_element(ofstream
&out
,
1909 t_field
efield(tset
->get_elem_type(), iter
);
1910 generate_serialize_field(out
, &efield
, "");
1914 * Serializes the members of a list.
1916 void t_php_generator::generate_serialize_list_element(ofstream
&out
,
1919 t_field
efield(tlist
->get_elem_type(), iter
);
1920 generate_serialize_field(out
, &efield
, "");
1924 * Declares a field, which may include initialization as necessary.
1926 * @param ttype The type
1928 string
t_php_generator::declare_field(t_field
* tfield
, bool init
, bool obj
) {
1929 string result
= "$" + tfield
->get_name();
1931 t_type
* type
= get_true_type(tfield
->get_type());
1932 if (type
->is_base_type()) {
1933 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
1935 case t_base_type::TYPE_VOID
:
1937 case t_base_type::TYPE_STRING
:
1940 case t_base_type::TYPE_BOOL
:
1941 result
+= " = false";
1943 case t_base_type::TYPE_BYTE
:
1944 case t_base_type::TYPE_I16
:
1945 case t_base_type::TYPE_I32
:
1946 case t_base_type::TYPE_I64
:
1949 case t_base_type::TYPE_DOUBLE
:
1953 throw "compiler error: no PHP initializer for base type " + t_base_type::t_base_name(tbase
);
1955 } else if (type
->is_enum()) {
1957 } else if (type
->is_container()) {
1958 result
+= " = array()";
1959 } else if (type
->is_struct() || type
->is_xception()) {
1961 result
+= " = new " + php_namespace(type
->get_program()) + type
->get_name() + "()";
1963 result
+= " = null";
1967 return result
+ ";";
1971 * Renders a function signature of the form 'type name(args)'
1973 * @param tfunction Function definition
1974 * @return String of rendered function definition
1976 string
t_php_generator::function_signature(t_function
* tfunction
,
1979 prefix
+ tfunction
->get_name() +
1980 "(" + argument_list(tfunction
->get_arglist()) + ")";
1984 * Renders a field list
1986 string
t_php_generator::argument_list(t_struct
* tstruct
) {
1989 const vector
<t_field
*>& fields
= tstruct
->get_members();
1990 vector
<t_field
*>::const_iterator f_iter
;
1992 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
1998 result
+= "$" + (*f_iter
)->get_name();
2004 * Gets a typecast string for a particular type.
2006 string
t_php_generator::type_to_cast(t_type
* type
) {
2007 if (type
->is_base_type()) {
2008 t_base_type
* btype
= (t_base_type
*)type
;
2009 switch (btype
->get_base()) {
2010 case t_base_type::TYPE_BOOL
:
2012 case t_base_type::TYPE_BYTE
:
2013 case t_base_type::TYPE_I16
:
2014 case t_base_type::TYPE_I32
:
2015 case t_base_type::TYPE_I64
:
2017 case t_base_type::TYPE_DOUBLE
:
2019 case t_base_type::TYPE_STRING
:
2024 } else if (type
->is_enum()) {
2031 * Converts the parse type to a C++ enum string for the given type.
2033 string
t_php_generator ::type_to_enum(t_type
* type
) {
2034 type
= get_true_type(type
);
2036 if (type
->is_base_type()) {
2037 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
2039 case t_base_type::TYPE_VOID
:
2040 throw "NO T_VOID CONSTRUCT";
2041 case t_base_type::TYPE_STRING
:
2042 return "TType::STRING";
2043 case t_base_type::TYPE_BOOL
:
2044 return "TType::BOOL";
2045 case t_base_type::TYPE_BYTE
:
2046 return "TType::BYTE";
2047 case t_base_type::TYPE_I16
:
2048 return "TType::I16";
2049 case t_base_type::TYPE_I32
:
2050 return "TType::I32";
2051 case t_base_type::TYPE_I64
:
2052 return "TType::I64";
2053 case t_base_type::TYPE_DOUBLE
:
2054 return "TType::DOUBLE";
2056 } else if (type
->is_enum()) {
2057 return "TType::I32";
2058 } else if (type
->is_struct() || type
->is_xception()) {
2059 return "TType::STRUCT";
2060 } else if (type
->is_map()) {
2061 return "TType::MAP";
2062 } else if (type
->is_set()) {
2063 return "TType::SET";
2064 } else if (type
->is_list()) {
2065 return "TType::LST";
2068 throw "INVALID TYPE IN type_to_enum: " + type
->get_name();