r1421@opsdev009 (orig r75230): mcslee | 2007-12-19 19:23:27 -0800
[amiethrift.git] / compiler / cpp / src / generate / t_php_generator.cc
blob5b3c979fa78f4e3b48c9b492dc5ea168c619a25a
1 // Copyright (c) 2006- Facebook
2 // Distributed under the Thrift Software License
3 //
4 // See accompanying file LICENSE or visit the Thrift site at:
5 // http://developers.facebook.com/thrift/
7 #include <stdlib.h>
8 #include <sys/stat.h>
9 #include <sstream>
10 #include "t_php_generator.h"
11 using namespace std;
13 /**
14 * Prepares for file generation by opening up the necessary file output
15 * streams.
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);
23 // Make output file
24 string f_types_name = get_out_dir()+program_name_+"_types.php";
25 f_types_.open(f_types_name.c_str());
27 // Print header
28 f_types_ <<
29 "<?php" << endl <<
30 autogen_comment() <<
31 php_includes();
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();
37 f_types_ <<
38 "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << package << "/" << package << "_types.php';" << endl;
40 f_types_ << endl;
42 // Print header
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());
46 f_consts_ <<
47 "<?php" << endl <<
48 autogen_comment() <<
49 "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" + program_name_ + "/" + program_name_ + "_types.php';" << endl <<
50 endl <<
51 "$GLOBALS['" << program_name_ << "_CONSTANTS'] = array(); " << endl <<
52 endl;
56 /**
57 * Prints standard php includes
59 string t_php_generator::php_includes() {
60 return
61 string("include_once $GLOBALS['THRIFT_ROOT'].'/Thrift.php';\n\n");
64 /**
65 * Close up (or down) some filez.
67 void t_php_generator::close_generator() {
68 // Close types file
69 f_types_ << "?>" << endl;
70 f_types_.close();
72 if (!program_->get_consts().empty()) {
73 f_consts_ << "?>" << endl;
74 f_consts_.close();
78 /**
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) {}
85 /**
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) {
92 f_types_ <<
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;
97 int value = -1;
98 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
99 if ((*c_iter)->has_value()) {
100 value = (*c_iter)->get_value();
101 } else {
102 ++value;
105 f_types_ <<
106 " '" << (*c_iter)->get_name() << "' => " << value << "," << endl;
109 f_types_ <<
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
115 // a downer.
116 f_types_ <<
117 "final class " << php_namespace(tenum->get_program()) << tenum->get_name() << " {" << endl;
118 indent_up();
120 value = -1;
121 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
122 if ((*c_iter)->has_value()) {
123 value = (*c_iter)->get_value();
124 } else {
125 ++value;
128 indent(f_types_) <<
129 "const " << (*c_iter)->get_name() << " = " << value << ";" << endl;
132 indent(f_types_) <<
133 "static public $__names = array(" << endl;
134 value = -1;
135 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
136 if ((*c_iter)->has_value()) {
137 value = (*c_iter)->get_value();
138 } else {
139 ++value;
142 indent(f_types_) <<
143 " " << value << " => '" << (*c_iter)->get_name() << "'," << endl;
145 indent(f_types_) <<
146 ");" << endl;
148 indent_down();
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();
175 switch (tbase) {
176 case t_base_type::TYPE_STRING:
177 out << "'" << value->get_string() << "'";
178 break;
179 case t_base_type::TYPE_BOOL:
180 out << (value->get_integer() > 0 ? "true" : "false");
181 break;
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();
187 break;
188 case t_base_type::TYPE_DOUBLE:
189 if (value->get_type() == t_const_value::CV_INTEGER) {
190 out << value->get_integer();
191 } else {
192 out << value->get_double();
194 break;
195 default:
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;
202 indent_up();
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();
217 out << indent();
218 out << render_const_value(g_type_string, v_iter->first);
219 out << " => ";
220 out << render_const_value(field_type, v_iter->second);
221 out << endl;
223 indent_down();
224 indent(out) << "))";
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;
229 indent_up();
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) {
233 out << indent();
234 out << render_const_value(ktype, v_iter->first);
235 out << " => ";
236 out << render_const_value(vtype, v_iter->second);
237 out << "," << endl;
239 indent_down();
240 indent(out) << ")";
241 } else if (type->is_list() || type->is_set()) {
242 t_type* etype;
243 if (type->is_list()) {
244 etype = ((t_list*)type)->get_elem_type();
245 } else {
246 etype = ((t_set*)type)->get_elem_type();
248 out << "array(" << endl;
249 indent_up();
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) {
253 out << indent();
254 out << render_const_value(etype, *v_iter);
255 if (type->is_set()) {
256 out << " => true";
258 out << "," << endl;
260 indent_down();
261 indent(out) << ")";
263 return out.str();
267 * Make a struct
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,
287 bool is_exception) {
288 generate_php_struct_definition(f_types_, tstruct, is_exception);
291 void t_php_generator::generate_php_type_spec(ofstream& out,
292 t_type* t) {
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;
306 indent_up();
307 generate_php_type_spec(out, ktype);
308 indent_down();
309 indent(out) << ")," << endl;
310 indent(out) << "'val' => array(" << endl;
311 indent_up();
312 generate_php_type_spec(out, vtype);
313 indent(out) << ")," << endl;
314 indent_down();
315 } else if (t->is_list() || t->is_set()) {
316 t_type* etype;
317 if (t->is_list()) {
318 etype = get_true_type(((t_list*)t)->get_elem_type());
319 } else {
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;
324 indent_up();
325 generate_php_type_spec(out, etype);
326 indent(out) << ")," << endl;
327 indent_down();
328 } else {
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,
339 t_struct* tstruct) {
340 indent(out) << "if (!isset(self::$_TSPEC)) {" << endl;
341 indent_up();
343 indent(out) << "self::$_TSPEC = array(" << endl;
344 indent_up();
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;
351 indent_up();
352 out <<
353 indent() << "'var' => '" << (*m_iter)->get_name() << "'," << endl;
354 generate_php_type_spec(out, t);
355 indent(out) << ")," << endl;
356 indent_down();
359 indent_down();
360 indent(out) << " );" << endl;
361 indent_down();
362 indent(out) << "}" << endl;
366 void t_php_generator::generate_php_struct_definition(ofstream& out,
367 t_struct* tstruct,
368 bool is_exception) {
369 if (autoload_) {
370 // Make output file
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();
380 f_types_ <<
381 "$GLOBALS['THRIFT_AUTOLOAD']['" << lowercase(php_namespace(tstruct->get_program()) + tstruct->get_name()) << "'] = '" << program_name_ << "/" << f_struct << "';" << endl;
383 } else {
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,
396 t_struct* tstruct,
397 bool is_exception) {
398 const vector<t_field*>& members = tstruct->get_members();
399 vector<t_field*>::const_iterator m_iter;
401 out <<
402 "class " << php_namespace(tstruct->get_program()) << tstruct->get_name();
403 if (is_exception) {
404 out << " extends TException";
405 } else if (oop_) {
406 out << " extends TBase";
408 out <<
409 " {" << endl;
410 indent_up();
412 if (oop_) {
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());
422 indent(out) <<
423 "public $" << (*m_iter)->get_name() << " = " << dval << ";" << endl;
426 out << endl;
428 // Generate constructor from array
429 if (oop_ || members.size() > 0) {
430 string param = (members.size() > 0) ? "$vals=null" : "";
431 out <<
432 indent() << "public function __construct(" << param << ") {" << endl;
433 indent_up();
435 if (oop_) {
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;
446 out <<
447 indent() << "if (is_array($vals)) {" << endl;
448 indent_up();
449 if (oop_) {
450 out << indent() << "parent::construct(self::$_TSPEC, $vals);" << endl;
451 } else {
452 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
453 out <<
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;
459 indent_down();
460 out <<
461 indent() << "}" << endl;
463 scope_down(out);
464 out << endl;
467 out <<
468 indent() << "public function getName() {" << endl <<
469 indent() << " return '" << tstruct->get_name() << "';" << endl <<
470 indent() << "}" << endl <<
471 endl;
473 generate_php_struct_reader(out, tstruct);
474 generate_php_struct_writer(out, tstruct);
476 indent_down();
477 out <<
478 indent() << "}" << endl <<
479 endl;
483 * Generates the read() method for a struct
485 void t_php_generator::generate_php_struct_reader(ofstream& out,
486 t_struct* tstruct) {
487 const vector<t_field*>& fields = tstruct->get_members();
488 vector<t_field*>::const_iterator f_iter;
490 indent(out) <<
491 "public function read($input)" << endl;
492 scope_up(out);
494 if (oop_) {
495 indent(out) << "return $this->_read('" << tstruct->get_name() << "', self::$_TSPEC, $input);" << endl;
496 scope_down(out);
497 return;
500 out <<
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_) {
508 indent(out) <<
509 "$xfer += $input->readStructBegin($fname);" << endl;
512 // Loop over reading in fields
513 indent(out) <<
514 "while (true)" << endl;
516 scope_up(out);
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);
523 out <<
524 indent() << "if ($ftype == TType::STOP) {" << endl <<
525 indent() << " break;" << endl <<
526 indent() << "}" << endl;
527 generate_deserialize_field(out, &ffid);
528 } else {
529 indent(out) <<
530 "$xfer += $input->readFieldBegin($fname, $ftype, $fid);" << endl;
531 // Check for field STOP marker and break
532 indent(out) <<
533 "if ($ftype == TType::STOP) {" << endl;
534 indent_up();
535 indent(out) <<
536 "break;" << endl;
537 indent_down();
538 indent(out) <<
539 "}" << endl;
542 // Switch statement on the field we are reading
543 indent(out) <<
544 "switch ($fid)" << endl;
546 scope_up(out);
548 // Generate deserialization code for known cases
549 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
550 indent(out) <<
551 "case " << (*f_iter)->get_key() << ":" << endl;
552 indent_up();
553 indent(out) << "if ($ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
554 indent_up();
555 generate_deserialize_field(out, *f_iter, "this->");
556 indent_down();
557 out <<
558 indent() << "} else {" << endl;
559 if (binary_inline_) {
560 indent(out) << " $xfer += TProtocol::skipBinary($input, $ftype);" << endl;
561 } else {
562 indent(out) << " $xfer += $input->skip($ftype);" << endl;
564 out <<
565 indent() << "}" << endl <<
566 indent() << "break;" << endl;
567 indent_down();
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;
574 } else {
575 indent(out) << " $xfer += $input->skip($ftype);" << endl;
577 indent(out) << " break;" << endl;
579 scope_down(out);
581 if (!binary_inline_) {
582 // Read field end marker
583 indent(out) <<
584 "$xfer += $input->readFieldEnd();" << endl;
587 scope_down(out);
589 if (!binary_inline_) {
590 indent(out) <<
591 "$xfer += $input->readStructEnd();" << endl;
594 indent(out) <<
595 "return $xfer;" << endl;
597 indent_down();
598 out <<
599 indent() << "}" << endl <<
600 endl;
604 * Generates the write() method for a struct
606 void t_php_generator::generate_php_struct_writer(ofstream& out,
607 t_struct* tstruct) {
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_) {
613 indent(out) <<
614 "public function write(&$output) {" << endl;
615 } else {
616 indent(out) <<
617 "public function write($output) {" << endl;
619 indent_up();
621 if (oop_) {
622 indent(out) << "return $this->_write('" << tstruct->get_name() << "', self::$_TSPEC, $output);" << endl;
623 scope_down(out);
624 return;
627 indent(out) <<
628 "$xfer = 0;" << endl;
630 if (!binary_inline_) {
631 indent(out) <<
632 "$xfer += $output->writeStructBegin('" << name << "');" << endl;
635 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
636 out <<
637 indent() << "if ($this->" << (*f_iter)->get_name() << " !== null) {" << endl;
638 indent_up();
640 // Write field header
641 if (binary_inline_) {
642 out <<
643 indent() << "$output .= pack('c', " << type_to_enum((*f_iter)->get_type()) << ");" << endl <<
644 indent() << "$output .= pack('n', " << (*f_iter)->get_key() << ");" << endl;
645 } else {
646 indent(out) <<
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_) {
658 indent(out) <<
659 "$xfer += $output->writeFieldEnd();" << endl;
662 indent_down();
663 indent(out) <<
664 "}" << endl;
667 if (binary_inline_) {
668 out <<
669 indent() << "$output .= pack('c', TType::STOP);" << endl;
670 } else {
671 out <<
672 indent() << "$xfer += $output->writeFieldStop();" << endl <<
673 indent() << "$xfer += $output->writeStructEnd();" << endl;
676 out <<
677 indent() << "return $xfer;" << endl;
679 indent_down();
680 out <<
681 indent() << "}" << endl <<
682 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());
694 f_service_ <<
695 "<?php" << endl <<
696 autogen_comment() <<
697 php_includes();
699 f_service_ <<
700 "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << program_name_ << "/" << program_name_ << "_types.php';" << endl;
702 if (tservice->get_extends() != NULL) {
703 f_service_ <<
704 "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << tservice->get_extends()->get_program()->get_name() << "/" << tservice->get_extends()->get_name() << ".php';" << endl;
707 f_service_ <<
708 endl;
710 // Generate the three main parts of the service (well, two for now in PHP)
711 generate_service_interface(tservice);
712 if (rest_) {
713 generate_service_rest(tservice);
715 generate_service_client(tservice);
716 generate_service_helpers(tservice);
717 if (phps_) {
718 generate_service_processor(tservice);
721 // Close service file
722 f_service_ << "?>" << endl;
723 f_service_.close();
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;
736 string extends = "";
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
744 f_service_ <<
745 "class " << service_name_ << "Processor" << extends_processor << " {" << endl;
746 indent_up();
748 if (extends.empty()) {
749 f_service_ <<
750 indent() << "protected $handler_ = null;" << endl;
753 f_service_ <<
754 indent() << "public function __construct($handler) {" << endl;
755 if (extends.empty()) {
756 f_service_ <<
757 indent() << " $this->handler_ = $handler;" << endl;
758 } else {
759 f_service_ <<
760 indent() << " parent::__construct($handler);" << endl;
762 f_service_ <<
763 indent() << "}" << endl <<
764 endl;
766 // Generate the server implementation
767 indent(f_service_) <<
768 "public function process($input, $output) {" << endl;
769 indent_up();
771 f_service_ <<
772 indent() << "$rseqid = 0;" << endl <<
773 indent() << "$fname = null;" << endl <<
774 indent() << "$mtype = 0;" << endl <<
775 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);
784 } else {
785 f_service_ <<
786 indent() << "$input->readMessageBegin($fname, $mtype, $rseqid);" << endl;
789 // HOT: check for method implementation
790 f_service_ <<
791 indent() << "$methodname = 'process_'.$fname;" << endl <<
792 indent() << "if (!method_exists($this, $methodname)) {" << endl;
793 if (binary_inline_) {
794 f_service_ <<
795 indent() << " throw new Exception('Function '.$fname.' not implemented.');" << endl;
796 } else {
797 f_service_ <<
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;
807 f_service_ <<
808 indent() << "}" << endl <<
809 indent() << "$this->$methodname($rseqid, $input, $output);" << endl <<
810 indent() << "return true;" << endl;
811 indent_down();
812 f_service_ <<
813 indent() << "}" << endl <<
814 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);
821 indent_down();
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) {
832 // Open function
833 indent(f_service_) <<
834 "protected function process_" << tfunction->get_name() <<
835 "($seqid, $input, $output) {" << endl;
836 indent_up();
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";
841 f_service_ <<
842 indent() << "$args = new " << argsname << "();" << endl <<
843 indent() << "$args->read($input);" << endl;
844 if (!binary_inline_) {
845 f_service_ <<
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()) {
855 f_service_ <<
856 indent() << "$result = new " << resultname << "();" << endl;
859 // Try block for a function with exceptions
860 if (xceptions.size() > 0) {
861 f_service_ <<
862 indent() << "try {" << endl;
863 indent_up();
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 = ";
875 f_service_ <<
876 "$this->handler_->" << tfunction->get_name() << "(";
877 bool first = true;
878 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
879 if (first) {
880 first = false;
881 } else {
882 f_service_ << ", ";
884 f_service_ << "$args->" << (*f_iter)->get_name();
886 f_service_ << ");" << endl;
888 if (!tfunction->is_async() && xceptions.size() > 0) {
889 indent_down();
890 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
891 f_service_ <<
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()) {
894 indent_up();
895 f_service_ <<
896 indent() << "$result->" << (*x_iter)->get_name() << " = $" << (*x_iter)->get_name() << ";" << endl;
897 indent_down();
898 f_service_ << indent();
901 f_service_ << "}" << endl;
904 // Shortcut out here for async functions
905 if (tfunction->is_async()) {
906 f_service_ <<
907 indent() << "return;" << endl;
908 indent_down();
909 f_service_ <<
910 indent() << "}" << endl;
911 return;
914 // Serialize the request header
915 if (binary_inline_) {
916 f_service_ <<
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;
924 } else {
925 f_service_ <<
926 indent() << "$output->writeMessageBegin('" << tfunction->get_name() << "', TMessageType::REPLY, $seqid);" << endl <<
927 indent() << "$result->write($output);" << endl <<
928 indent() << "$output->getTransport()->flush();" << endl;
931 // Close function
932 indent_down();
933 f_service_ <<
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;
946 f_service_ <<
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);
955 ts->set_name(name);
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) {
989 string extends = "";
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";
995 f_service_ <<
996 "interface " << service_name_ << "If" << extends_if << " {" << endl;
997 indent_up();
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;
1004 indent_down();
1005 f_service_ <<
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";
1019 f_service_ <<
1020 "class " << service_name_ << "Rest" << extends_if << " {" << endl;
1021 indent_up();
1023 if (extends.empty()) {
1024 f_service_ <<
1025 indent() << "protected $impl_;" << endl <<
1026 endl;
1029 f_service_ <<
1030 indent() << "public function __construct($impl) {" << endl <<
1031 indent() << " $this->impl_ = $impl;" << endl <<
1032 indent() << "}" << endl <<
1033 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;
1040 indent_up();
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()) {
1048 f_service_ <<
1049 indent() << "$" << (*a_iter)->get_name() << " = " << cast << "(!empty(" << req << ") && (" << req << " !== 'false'));" << endl;
1050 } else {
1051 f_service_ <<
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()) {
1056 f_service_ <<
1057 indent() << "$" << (*a_iter)->get_name() << " = explode(',', $" << (*a_iter)->get_name() << ");" << endl;
1058 } else if (atype->is_map() || atype->is_list()) {
1059 f_service_ <<
1060 indent() << "$" << (*a_iter)->get_name() << " = json_decode($" << (*a_iter)->get_name() << ", true);" << endl;
1061 } else if (atype->is_set()) {
1062 f_service_ <<
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()) {
1065 f_service_ <<
1066 indent() << "$" << (*a_iter)->get_name() << " = new " << php_namespace(atype->get_program()) << atype->get_name() << "(json_decode($" << (*a_iter)->get_name() << ", true));" << endl;
1069 f_service_ <<
1070 indent() << "return $this->impl_->" << (*f_iter)->get_name() << "(" << argument_list((*f_iter)->get_arglist()) << ");" << endl;
1071 indent_down();
1072 indent(f_service_) <<
1073 "}" << endl <<
1074 endl;
1076 indent_down();
1077 f_service_ <<
1078 "}" << endl << endl;
1081 void t_php_generator::generate_service_client(t_service* tservice) {
1082 if (autoload_) {
1083 // Make output file
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();
1093 f_service_ <<
1094 "$GLOBALS['THRIFT_AUTOLOAD']['" << lowercase(service_name_ + "Client") << "'] = '" << program_name_ << "/" << f_struct << "';" << endl;
1096 } else {
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";
1114 out <<
1115 "class " << service_name_ << "Client" << extends_client << " implements " << service_name_ << "If {" << endl;
1116 indent_up();
1118 // Private members
1119 if (extends.empty()) {
1120 out <<
1121 indent() << "protected $input_ = null;" << endl <<
1122 indent() << "protected $output_ = null;" << endl <<
1123 endl;
1124 out <<
1125 indent() << "protected $seqid_ = 0;" << endl <<
1126 endl;
1129 // Constructor function
1130 out <<
1131 indent() << "public function __construct($input, $output=null) {" << endl;
1132 if (!extends.empty()) {
1133 out <<
1134 indent() << " parent::__construct($input, $output);" << endl;
1135 } else {
1136 out <<
1137 indent() << " $this->input_ = $input;" << endl <<
1138 indent() << " $this->output_ = $output ? $output : $input;" << endl;
1140 out <<
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();
1152 // Open function
1153 indent(out) <<
1154 "public function " << function_signature(*f_iter) << endl;
1155 scope_up(out);
1156 indent(out) <<
1157 "$this->send_" << funname << "(";
1159 bool first = true;
1160 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1161 if (first) {
1162 first = false;
1163 } else {
1164 out << ", ";
1166 out << "$" << (*fld_iter)->get_name();
1168 out << ");" << endl;
1170 if (!(*f_iter)->is_async()) {
1171 out << indent();
1172 if (!(*f_iter)->get_returntype()->is_void()) {
1173 out << "return ";
1175 out <<
1176 "$this->recv_" << funname << "();" << endl;
1178 scope_down(out);
1179 out << endl;
1181 indent(out) <<
1182 "public function send_" << function_signature(*f_iter) << endl;
1183 scope_up(out);
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_) {
1189 out <<
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;
1194 } else {
1195 out <<
1196 indent() << "$this->output_->writeMessageBegin('" << (*f_iter)->get_name() << "', TMessageType::CALL, $this->seqid_);" << endl;
1199 out <<
1200 indent() << "$args = new " << argsname << "();" << endl;
1202 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1203 out <<
1204 indent() << "$args->" << (*fld_iter)->get_name() << " = $" << (*fld_iter)->get_name() << ";" << endl;
1207 // Write to the stream
1208 if (binary_inline_) {
1209 out <<
1210 indent() << "$args->write($buff);" << endl <<
1211 indent() << "$this->output_->write($buff);" << endl <<
1212 indent() << "$this->output_->flush();" << endl;
1213 } else {
1214 out <<
1215 indent() << "$args->write($this->output_);" << endl <<
1216 indent() << "$this->output_->writeMessageEnd();" << endl <<
1217 indent() << "$this->output_->getTransport()->flush();" << endl;
1220 scope_down(out);
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(),
1229 &noargs);
1230 // Open function
1231 out <<
1232 endl <<
1233 indent() << "public function " << function_signature(&recv_function) << endl;
1234 scope_up(out);
1236 out <<
1237 indent() << "$rseqid = 0;" << endl <<
1238 indent() << "$fname = null;" << endl <<
1239 indent() << "$mtype = 0;" << endl <<
1240 endl;
1242 if (binary_inline_) {
1243 t_field ffname(g_type_string, "fname");
1244 t_field fseqid(g_type_i32, "rseqid");
1245 out <<
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);
1253 } else {
1254 out <<
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;
1264 out <<
1265 indent() << "$result = new " << resultname << "();" << endl <<
1266 indent() << "$result->read($this->input_);" << endl;
1268 if (!binary_inline_) {
1269 out <<
1270 indent() << "$this->input_->readMessageEnd();" << endl <<
1271 endl;
1274 // Careful, only return result if not a void function
1275 if (!(*f_iter)->get_returntype()->is_void()) {
1276 out <<
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) {
1286 out <<
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()) {
1294 indent(out) <<
1295 "return;" << endl;
1296 } else {
1297 out <<
1298 indent() << "throw new Exception(\"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
1301 // Close function
1302 scope_down(out);
1303 out << endl;
1308 indent_down();
1309 out <<
1310 "}" << endl << endl;
1314 * Deserializes a field of any type.
1316 void t_php_generator::generate_deserialize_field(ofstream &out,
1317 t_field* tfield,
1318 string prefix,
1319 bool inclass) {
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,
1331 (t_struct*)type,
1332 name);
1333 } else {
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;
1340 indent_up();
1341 string ttype_name;
1342 if (type->is_enum()) {
1343 ttype_name = "I32";
1344 } else {
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;
1352 indent_down();
1353 out << indent() << "} else {" << endl;
1354 indent_up();
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();
1362 switch (tbase) {
1363 case t_base_type::TYPE_VOID:
1364 throw "compiler error: cannot serialize void field in a struct: " +
1365 name;
1366 break;
1367 case t_base_type::TYPE_STRING:
1368 out <<
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;
1375 break;
1376 case t_base_type::TYPE_BOOL:
1377 out <<
1378 indent() << "$" << name << " = unpack('c', " << itrans << "->readAll(1));" << endl <<
1379 indent() << "$" << name << " = (bool)$" << name << "[1];" << endl;
1380 break;
1381 case t_base_type::TYPE_BYTE:
1382 out <<
1383 indent() << "$" << name << " = unpack('c', " << itrans << "->readAll(1));" << endl <<
1384 indent() << "$" << name << " = $" << name << "[1];" << endl;
1385 break;
1386 case t_base_type::TYPE_I16:
1387 out <<
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;
1394 break;
1395 case t_base_type::TYPE_I32:
1396 out <<
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;
1403 break;
1404 case t_base_type::TYPE_I64:
1405 out <<
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;
1414 break;
1415 case t_base_type::TYPE_DOUBLE:
1416 out <<
1417 indent() << "$arr = unpack('d', strrev(" << itrans << "->readAll(8)));" << endl <<
1418 indent() << "$" << name << " = $arr[1];" << endl;
1419 break;
1420 default:
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()) {
1424 out <<
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;
1432 } else {
1434 indent(out) <<
1435 "$xfer += $input->";
1437 if (type->is_base_type()) {
1438 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1439 switch (tbase) {
1440 case t_base_type::TYPE_VOID:
1441 throw "compiler error: cannot serialize void field in a struct: " +
1442 name;
1443 break;
1444 case t_base_type::TYPE_STRING:
1445 out << "readString($" << name << ");";
1446 break;
1447 case t_base_type::TYPE_BOOL:
1448 out << "readBool($" << name << ");";
1449 break;
1450 case t_base_type::TYPE_BYTE:
1451 out << "readByte($" << name << ");";
1452 break;
1453 case t_base_type::TYPE_I16:
1454 out << "readI16($" << name << ");";
1455 break;
1456 case t_base_type::TYPE_I32:
1457 out << "readI32($" << name << ");";
1458 break;
1459 case t_base_type::TYPE_I64:
1460 out << "readI64($" << name << ");";
1461 break;
1462 case t_base_type::TYPE_DOUBLE:
1463 out << "readDouble($" << name << ");";
1464 break;
1465 default:
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 << ");";
1471 out << endl;
1473 out << indent() << "}" << endl;
1474 indent_down();
1475 } else {
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,
1489 t_struct* tstruct,
1490 string prefix) {
1491 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,
1497 t_type* ttype,
1498 string prefix) {
1499 out << indent() << "if (($input instanceof TProtocol::$TBINARYPROTOCOLACCELERATED) && function_exists('thrift_protocol_binary_deserialize'))" << endl;
1500 scope_up(out);
1502 string ttype_name;
1503 t_type* tvaluetype = NULL;
1504 if (ttype->is_map()) {
1505 ttype_name = "MAP";
1506 tvaluetype = reinterpret_cast<t_map*>(ttype)->get_val_type();
1507 } else if (ttype->is_set()) {
1508 ttype_name = "SET";
1509 tvaluetype = reinterpret_cast<t_set*>(ttype)->get_elem_type();
1510 } else if (ttype->is_list()) {
1511 ttype_name = "LST";
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;
1516 } else {
1517 out << indent() << "$" << prefix << " = thrift_protocol_binary_deserialize(TType::" << ttype_name << ", $input);" << endl;
1519 scope_down(out);
1520 out << indent() << "else" << endl;
1521 scope_up(out);
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);
1533 out <<
1534 indent() << "$" << prefix << " = array();" << endl <<
1535 indent() << "$" << size << " = 0;" << endl;
1537 // Declare variables, read header
1538 if (ttype->is_map()) {
1539 out <<
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);
1546 } else {
1547 out <<
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);
1555 } else {
1556 out <<
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);
1565 } else {
1566 out <<
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");
1575 indent(out) <<
1576 "for ($" <<
1577 i << " = 0; $" << i << " < $" << size << "; ++$" << i << ")" << endl;
1579 scope_up(out);
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);
1589 scope_down(out);
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;
1602 scope_down(out);
1607 * Generates code to deserialize a map
1609 void t_php_generator::generate_deserialize_map_element(ofstream &out,
1610 t_map* tmap,
1611 string prefix) {
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);
1617 indent(out) <<
1618 declare_field(&fkey, true, true) << endl;
1619 indent(out) <<
1620 declare_field(&fval, true, true) << endl;
1622 generate_deserialize_field(out, &fkey);
1623 generate_deserialize_field(out, &fval);
1625 indent(out) <<
1626 "$" << prefix << "[$" << key << "] = $" << val << ";" << endl;
1629 void t_php_generator::generate_deserialize_set_element(ofstream &out,
1630 t_set* tset,
1631 string prefix) {
1632 string elem = tmp("elem");
1633 t_field felem(tset->get_elem_type(), elem);
1635 indent(out) <<
1636 "$" << elem << " = null;" << endl;
1638 generate_deserialize_field(out, &felem);
1640 indent(out) <<
1641 "$" << prefix << "[$" << elem << "] = true;" << endl;
1644 void t_php_generator::generate_deserialize_list_element(ofstream &out,
1645 t_list* tlist,
1646 string prefix) {
1647 string elem = tmp("elem");
1648 t_field felem(tlist->get_elem_type(), elem);
1650 indent(out) <<
1651 "$" << elem << " = null;" << endl;
1653 generate_deserialize_field(out, &felem);
1655 indent(out) <<
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,
1667 t_field* tfield,
1668 string prefix) {
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,
1679 (t_struct*)type,
1680 prefix + tfield->get_name());
1681 } else if (type->is_container()) {
1682 generate_serialize_container(out,
1683 type,
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();
1692 switch (tbase) {
1693 case t_base_type::TYPE_VOID:
1694 throw
1695 "compiler error: cannot serialize void field in a struct: " + name;
1696 break;
1697 case t_base_type::TYPE_STRING:
1698 out <<
1699 indent() << "$output .= pack('N', strlen($" << name << "));" << endl <<
1700 indent() << "$output .= $" << name << ";" << endl;
1701 break;
1702 case t_base_type::TYPE_BOOL:
1703 out <<
1704 indent() << "$output .= pack('c', $" << name << " ? 1 : 0);" << endl;
1705 break;
1706 case t_base_type::TYPE_BYTE:
1707 out <<
1708 indent() << "$output .= pack('c', $" << name << ");" << endl;
1709 break;
1710 case t_base_type::TYPE_I16:
1711 out <<
1712 indent() << "$output .= pack('n', $" << name << ");" << endl;
1713 break;
1714 case t_base_type::TYPE_I32:
1715 out <<
1716 indent() << "$output .= pack('N', $" << name << ");" << endl;
1717 break;
1718 case t_base_type::TYPE_I64:
1719 out <<
1720 indent() << "$output .= pack('N2', $" << name << " >> 32, $" << name << " & 0xFFFFFFFF);" << endl;
1721 break;
1722 case t_base_type::TYPE_DOUBLE:
1723 out <<
1724 indent() << "$output .= strrev(pack('d', $" << name << "));" << endl;
1725 break;
1726 default:
1727 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase);
1729 } else if (type->is_enum()) {
1730 out <<
1731 indent() << "$output .= pack('N', $" << name << ");" << endl;
1733 } else {
1735 indent(out) <<
1736 "$xfer += $output->";
1738 if (type->is_base_type()) {
1739 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1740 switch (tbase) {
1741 case t_base_type::TYPE_VOID:
1742 throw
1743 "compiler error: cannot serialize void field in a struct: " + name;
1744 break;
1745 case t_base_type::TYPE_STRING:
1746 out << "writeString($" << name << ");";
1747 break;
1748 case t_base_type::TYPE_BOOL:
1749 out << "writeBool($" << name << ");";
1750 break;
1751 case t_base_type::TYPE_BYTE:
1752 out << "writeByte($" << name << ");";
1753 break;
1754 case t_base_type::TYPE_I16:
1755 out << "writeI16($" << name << ");";
1756 break;
1757 case t_base_type::TYPE_I32:
1758 out << "writeI32($" << name << ");";
1759 break;
1760 case t_base_type::TYPE_I64:
1761 out << "writeI64($" << name << ");";
1762 break;
1763 case t_base_type::TYPE_DOUBLE:
1764 out << "writeDouble($" << name << ");";
1765 break;
1766 default:
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 << ");";
1772 out << endl;
1774 } else {
1775 printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
1776 prefix.c_str(),
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,
1789 t_struct* tstruct,
1790 string prefix) {
1791 indent(out) <<
1792 "$xfer += $" << prefix << "->write($output);" << endl;
1796 * Writes out a container
1798 void t_php_generator::generate_serialize_container(ofstream &out,
1799 t_type* ttype,
1800 string prefix) {
1801 scope_up(out);
1803 if (ttype->is_map()) {
1804 if (binary_inline_) {
1805 out <<
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;
1809 } else {
1810 indent(out) <<
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_) {
1818 out <<
1819 indent() << "$output .= pack('c', " << type_to_enum(((t_set*)ttype)->get_elem_type()) << ");" << endl <<
1820 indent() << "$output .= strrev(pack('l', count($" << prefix << ")));" << endl;
1822 } else {
1823 indent(out) <<
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_) {
1830 out <<
1831 indent() << "$output .= pack('c', " << type_to_enum(((t_list*)ttype)->get_elem_type()) << ");" << endl <<
1832 indent() << "$output .= strrev(pack('l', count($" << prefix << ")));" << endl;
1834 } else {
1835 indent(out) <<
1836 "$output->writeListBegin(" <<
1837 type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
1838 "count($" << prefix << "));" << endl;
1842 scope_up(out);
1844 if (ttype->is_map()) {
1845 string kiter = tmp("kiter");
1846 string viter = tmp("viter");
1847 indent(out) <<
1848 "foreach ($" << prefix << " as " <<
1849 "$" << kiter << " => $" << viter << ")" << endl;
1850 scope_up(out);
1851 generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
1852 scope_down(out);
1853 } else if (ttype->is_set()) {
1854 string iter = tmp("iter");
1855 indent(out) <<
1856 "foreach ($" << prefix << " as $" << iter << " => $true)" << endl;
1857 scope_up(out);
1858 generate_serialize_set_element(out, (t_set*)ttype, iter);
1859 scope_down(out);
1860 } else if (ttype->is_list()) {
1861 string iter = tmp("iter");
1862 indent(out) <<
1863 "foreach ($" << prefix << " as $" << iter << ")" << endl;
1864 scope_up(out);
1865 generate_serialize_list_element(out, (t_list*)ttype, iter);
1866 scope_down(out);
1869 scope_down(out);
1871 if (!binary_inline_) {
1872 if (ttype->is_map()) {
1873 indent(out) <<
1874 "$output->writeMapEnd();" << endl;
1875 } else if (ttype->is_set()) {
1876 indent(out) <<
1877 "$output->writeSetEnd();" << endl;
1878 } else if (ttype->is_list()) {
1879 indent(out) <<
1880 "$output->writeListEnd();" << endl;
1884 scope_down(out);
1888 * Serializes the members of a map.
1891 void t_php_generator::generate_serialize_map_element(ofstream &out,
1892 t_map* tmap,
1893 string kiter,
1894 string viter) {
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,
1906 t_set* tset,
1907 string iter) {
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,
1916 t_list* tlist,
1917 string iter) {
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();
1929 if (init) {
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();
1933 switch (tbase) {
1934 case t_base_type::TYPE_VOID:
1935 break;
1936 case t_base_type::TYPE_STRING:
1937 result += " = ''";
1938 break;
1939 case t_base_type::TYPE_BOOL:
1940 result += " = false";
1941 break;
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:
1946 result += " = 0";
1947 break;
1948 case t_base_type::TYPE_DOUBLE:
1949 result += " = 0.0";
1950 break;
1951 default:
1952 throw "compiler error: no PHP initializer for base type " + t_base_type::t_base_name(tbase);
1954 } else if (type->is_enum()) {
1955 result += " = 0";
1956 } else if (type->is_container()) {
1957 result += " = array()";
1958 } else if (type->is_struct() || type->is_xception()) {
1959 if (obj) {
1960 result += " = new " + php_namespace(type->get_program()) + type->get_name() + "()";
1961 } else {
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,
1976 string prefix) {
1977 return
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) {
1986 string result = "";
1988 const vector<t_field*>& fields = tstruct->get_members();
1989 vector<t_field*>::const_iterator f_iter;
1990 bool first = true;
1991 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1992 if (first) {
1993 first = false;
1994 } else {
1995 result += ", ";
1997 result += "$" + (*f_iter)->get_name();
1999 return result;
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:
2010 return "(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:
2015 return "(int)";
2016 case t_base_type::TYPE_DOUBLE:
2017 return "(double)";
2018 case t_base_type::TYPE_STRING:
2019 return "(string)";
2020 default:
2021 return "";
2023 } else if (type->is_enum()) {
2024 return "(int)";
2026 return "";
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();
2037 switch (tbase) {
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();