r1459@opsdev009 (orig r77477): dreiss | 2008-01-11 12:59:03 -0800
[amiethrift.git] / compiler / cpp / src / generate / t_php_generator.cc
blob1f4ed1fcb3d76fa898c7ed0697ac4eab0f7f2ee7
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 #include "platform.h"
12 using namespace std;
14 /**
15 * Prepares for file generation by opening up the necessary file output
16 * streams.
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());
24 // Make output file
25 string f_types_name = get_out_dir()+program_name_+"_types.php";
26 f_types_.open(f_types_name.c_str());
28 // Print header
29 f_types_ <<
30 "<?php" << endl <<
31 autogen_comment() <<
32 php_includes();
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();
38 f_types_ <<
39 "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << package << "/" << package << "_types.php';" << endl;
41 f_types_ << endl;
43 // Print header
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());
47 f_consts_ <<
48 "<?php" << endl <<
49 autogen_comment() <<
50 "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" + program_name_ + "/" + program_name_ + "_types.php';" << endl <<
51 endl <<
52 "$GLOBALS['" << program_name_ << "_CONSTANTS'] = array(); " << endl <<
53 endl;
57 /**
58 * Prints standard php includes
60 string t_php_generator::php_includes() {
61 return
62 string("include_once $GLOBALS['THRIFT_ROOT'].'/Thrift.php';\n\n");
65 /**
66 * Close up (or down) some filez.
68 void t_php_generator::close_generator() {
69 // Close types file
70 f_types_ << "?>" << endl;
71 f_types_.close();
73 if (!program_->get_consts().empty()) {
74 f_consts_ << "?>" << endl;
75 f_consts_.close();
79 /**
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) {}
86 /**
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) {
93 f_types_ <<
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;
98 int value = -1;
99 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
100 if ((*c_iter)->has_value()) {
101 value = (*c_iter)->get_value();
102 } else {
103 ++value;
106 f_types_ <<
107 " '" << (*c_iter)->get_name() << "' => " << value << "," << endl;
110 f_types_ <<
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
116 // a downer.
117 f_types_ <<
118 "final class " << php_namespace(tenum->get_program()) << tenum->get_name() << " {" << endl;
119 indent_up();
121 value = -1;
122 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
123 if ((*c_iter)->has_value()) {
124 value = (*c_iter)->get_value();
125 } else {
126 ++value;
129 indent(f_types_) <<
130 "const " << (*c_iter)->get_name() << " = " << value << ";" << endl;
133 indent(f_types_) <<
134 "static public $__names = array(" << endl;
135 value = -1;
136 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
137 if ((*c_iter)->has_value()) {
138 value = (*c_iter)->get_value();
139 } else {
140 ++value;
143 indent(f_types_) <<
144 " " << value << " => '" << (*c_iter)->get_name() << "'," << endl;
146 indent(f_types_) <<
147 ");" << endl;
149 indent_down();
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();
176 switch (tbase) {
177 case t_base_type::TYPE_STRING:
178 out << "'" << value->get_string() << "'";
179 break;
180 case t_base_type::TYPE_BOOL:
181 out << (value->get_integer() > 0 ? "true" : "false");
182 break;
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();
188 break;
189 case t_base_type::TYPE_DOUBLE:
190 if (value->get_type() == t_const_value::CV_INTEGER) {
191 out << value->get_integer();
192 } else {
193 out << value->get_double();
195 break;
196 default:
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;
203 indent_up();
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();
218 out << indent();
219 out << render_const_value(g_type_string, v_iter->first);
220 out << " => ";
221 out << render_const_value(field_type, v_iter->second);
222 out << endl;
224 indent_down();
225 indent(out) << "))";
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;
230 indent_up();
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) {
234 out << indent();
235 out << render_const_value(ktype, v_iter->first);
236 out << " => ";
237 out << render_const_value(vtype, v_iter->second);
238 out << "," << endl;
240 indent_down();
241 indent(out) << ")";
242 } else if (type->is_list() || type->is_set()) {
243 t_type* etype;
244 if (type->is_list()) {
245 etype = ((t_list*)type)->get_elem_type();
246 } else {
247 etype = ((t_set*)type)->get_elem_type();
249 out << "array(" << endl;
250 indent_up();
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) {
254 out << indent();
255 out << render_const_value(etype, *v_iter);
256 if (type->is_set()) {
257 out << " => true";
259 out << "," << endl;
261 indent_down();
262 indent(out) << ")";
264 return out.str();
268 * Make a struct
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,
288 bool is_exception) {
289 generate_php_struct_definition(f_types_, tstruct, is_exception);
292 void t_php_generator::generate_php_type_spec(ofstream& out,
293 t_type* t) {
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;
307 indent_up();
308 generate_php_type_spec(out, ktype);
309 indent_down();
310 indent(out) << ")," << endl;
311 indent(out) << "'val' => array(" << endl;
312 indent_up();
313 generate_php_type_spec(out, vtype);
314 indent(out) << ")," << endl;
315 indent_down();
316 } else if (t->is_list() || t->is_set()) {
317 t_type* etype;
318 if (t->is_list()) {
319 etype = get_true_type(((t_list*)t)->get_elem_type());
320 } else {
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;
325 indent_up();
326 generate_php_type_spec(out, etype);
327 indent(out) << ")," << endl;
328 indent_down();
329 } else {
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,
340 t_struct* tstruct) {
341 indent(out) << "if (!isset(self::$_TSPEC)) {" << endl;
342 indent_up();
344 indent(out) << "self::$_TSPEC = array(" << endl;
345 indent_up();
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;
352 indent_up();
353 out <<
354 indent() << "'var' => '" << (*m_iter)->get_name() << "'," << endl;
355 generate_php_type_spec(out, t);
356 indent(out) << ")," << endl;
357 indent_down();
360 indent_down();
361 indent(out) << " );" << endl;
362 indent_down();
363 indent(out) << "}" << endl;
367 void t_php_generator::generate_php_struct_definition(ofstream& out,
368 t_struct* tstruct,
369 bool is_exception) {
370 if (autoload_) {
371 // Make output file
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();
381 f_types_ <<
382 "$GLOBALS['THRIFT_AUTOLOAD']['" << lowercase(php_namespace(tstruct->get_program()) + tstruct->get_name()) << "'] = '" << program_name_ << "/" << f_struct << "';" << endl;
384 } else {
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,
397 t_struct* tstruct,
398 bool is_exception) {
399 const vector<t_field*>& members = tstruct->get_members();
400 vector<t_field*>::const_iterator m_iter;
402 out <<
403 "class " << php_namespace(tstruct->get_program()) << tstruct->get_name();
404 if (is_exception) {
405 out << " extends TException";
406 } else if (oop_) {
407 out << " extends TBase";
409 out <<
410 " {" << endl;
411 indent_up();
413 if (oop_) {
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());
423 indent(out) <<
424 "public $" << (*m_iter)->get_name() << " = " << dval << ";" << endl;
427 out << endl;
429 // Generate constructor from array
430 if (oop_ || members.size() > 0) {
431 string param = (members.size() > 0) ? "$vals=null" : "";
432 out <<
433 indent() << "public function __construct(" << param << ") {" << endl;
434 indent_up();
436 if (oop_) {
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;
447 out <<
448 indent() << "if (is_array($vals)) {" << endl;
449 indent_up();
450 if (oop_) {
451 out << indent() << "parent::construct(self::$_TSPEC, $vals);" << endl;
452 } else {
453 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
454 out <<
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;
460 indent_down();
461 out <<
462 indent() << "}" << endl;
464 scope_down(out);
465 out << endl;
468 out <<
469 indent() << "public function getName() {" << endl <<
470 indent() << " return '" << tstruct->get_name() << "';" << endl <<
471 indent() << "}" << endl <<
472 endl;
474 generate_php_struct_reader(out, tstruct);
475 generate_php_struct_writer(out, tstruct);
477 indent_down();
478 out <<
479 indent() << "}" << endl <<
480 endl;
484 * Generates the read() method for a struct
486 void t_php_generator::generate_php_struct_reader(ofstream& out,
487 t_struct* tstruct) {
488 const vector<t_field*>& fields = tstruct->get_members();
489 vector<t_field*>::const_iterator f_iter;
491 indent(out) <<
492 "public function read($input)" << endl;
493 scope_up(out);
495 if (oop_) {
496 indent(out) << "return $this->_read('" << tstruct->get_name() << "', self::$_TSPEC, $input);" << endl;
497 scope_down(out);
498 return;
501 out <<
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_) {
509 indent(out) <<
510 "$xfer += $input->readStructBegin($fname);" << endl;
513 // Loop over reading in fields
514 indent(out) <<
515 "while (true)" << endl;
517 scope_up(out);
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);
524 out <<
525 indent() << "if ($ftype == TType::STOP) {" << endl <<
526 indent() << " break;" << endl <<
527 indent() << "}" << endl;
528 generate_deserialize_field(out, &ffid);
529 } else {
530 indent(out) <<
531 "$xfer += $input->readFieldBegin($fname, $ftype, $fid);" << endl;
532 // Check for field STOP marker and break
533 indent(out) <<
534 "if ($ftype == TType::STOP) {" << endl;
535 indent_up();
536 indent(out) <<
537 "break;" << endl;
538 indent_down();
539 indent(out) <<
540 "}" << endl;
543 // Switch statement on the field we are reading
544 indent(out) <<
545 "switch ($fid)" << endl;
547 scope_up(out);
549 // Generate deserialization code for known cases
550 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
551 indent(out) <<
552 "case " << (*f_iter)->get_key() << ":" << endl;
553 indent_up();
554 indent(out) << "if ($ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
555 indent_up();
556 generate_deserialize_field(out, *f_iter, "this->");
557 indent_down();
558 out <<
559 indent() << "} else {" << endl;
560 if (binary_inline_) {
561 indent(out) << " $xfer += TProtocol::skipBinary($input, $ftype);" << endl;
562 } else {
563 indent(out) << " $xfer += $input->skip($ftype);" << endl;
565 out <<
566 indent() << "}" << endl <<
567 indent() << "break;" << endl;
568 indent_down();
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;
575 } else {
576 indent(out) << " $xfer += $input->skip($ftype);" << endl;
578 indent(out) << " break;" << endl;
580 scope_down(out);
582 if (!binary_inline_) {
583 // Read field end marker
584 indent(out) <<
585 "$xfer += $input->readFieldEnd();" << endl;
588 scope_down(out);
590 if (!binary_inline_) {
591 indent(out) <<
592 "$xfer += $input->readStructEnd();" << endl;
595 indent(out) <<
596 "return $xfer;" << endl;
598 indent_down();
599 out <<
600 indent() << "}" << endl <<
601 endl;
605 * Generates the write() method for a struct
607 void t_php_generator::generate_php_struct_writer(ofstream& out,
608 t_struct* tstruct) {
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_) {
614 indent(out) <<
615 "public function write(&$output) {" << endl;
616 } else {
617 indent(out) <<
618 "public function write($output) {" << endl;
620 indent_up();
622 if (oop_) {
623 indent(out) << "return $this->_write('" << tstruct->get_name() << "', self::$_TSPEC, $output);" << endl;
624 scope_down(out);
625 return;
628 indent(out) <<
629 "$xfer = 0;" << endl;
631 if (!binary_inline_) {
632 indent(out) <<
633 "$xfer += $output->writeStructBegin('" << name << "');" << endl;
636 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
637 out <<
638 indent() << "if ($this->" << (*f_iter)->get_name() << " !== null) {" << endl;
639 indent_up();
641 // Write field header
642 if (binary_inline_) {
643 out <<
644 indent() << "$output .= pack('c', " << type_to_enum((*f_iter)->get_type()) << ");" << endl <<
645 indent() << "$output .= pack('n', " << (*f_iter)->get_key() << ");" << endl;
646 } else {
647 indent(out) <<
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_) {
659 indent(out) <<
660 "$xfer += $output->writeFieldEnd();" << endl;
663 indent_down();
664 indent(out) <<
665 "}" << endl;
668 if (binary_inline_) {
669 out <<
670 indent() << "$output .= pack('c', TType::STOP);" << endl;
671 } else {
672 out <<
673 indent() << "$xfer += $output->writeFieldStop();" << endl <<
674 indent() << "$xfer += $output->writeStructEnd();" << endl;
677 out <<
678 indent() << "return $xfer;" << endl;
680 indent_down();
681 out <<
682 indent() << "}" << endl <<
683 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());
695 f_service_ <<
696 "<?php" << endl <<
697 autogen_comment() <<
698 php_includes();
700 f_service_ <<
701 "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << program_name_ << "/" << program_name_ << "_types.php';" << endl;
703 if (tservice->get_extends() != NULL) {
704 f_service_ <<
705 "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << tservice->get_extends()->get_program()->get_name() << "/" << tservice->get_extends()->get_name() << ".php';" << endl;
708 f_service_ <<
709 endl;
711 // Generate the three main parts of the service (well, two for now in PHP)
712 generate_service_interface(tservice);
713 if (rest_) {
714 generate_service_rest(tservice);
716 generate_service_client(tservice);
717 generate_service_helpers(tservice);
718 if (phps_) {
719 generate_service_processor(tservice);
722 // Close service file
723 f_service_ << "?>" << endl;
724 f_service_.close();
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;
737 string extends = "";
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
745 f_service_ <<
746 "class " << service_name_ << "Processor" << extends_processor << " {" << endl;
747 indent_up();
749 if (extends.empty()) {
750 f_service_ <<
751 indent() << "protected $handler_ = null;" << endl;
754 f_service_ <<
755 indent() << "public function __construct($handler) {" << endl;
756 if (extends.empty()) {
757 f_service_ <<
758 indent() << " $this->handler_ = $handler;" << endl;
759 } else {
760 f_service_ <<
761 indent() << " parent::__construct($handler);" << endl;
763 f_service_ <<
764 indent() << "}" << endl <<
765 endl;
767 // Generate the server implementation
768 indent(f_service_) <<
769 "public function process($input, $output) {" << endl;
770 indent_up();
772 f_service_ <<
773 indent() << "$rseqid = 0;" << endl <<
774 indent() << "$fname = null;" << endl <<
775 indent() << "$mtype = 0;" << endl <<
776 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);
785 } else {
786 f_service_ <<
787 indent() << "$input->readMessageBegin($fname, $mtype, $rseqid);" << endl;
790 // HOT: check for method implementation
791 f_service_ <<
792 indent() << "$methodname = 'process_'.$fname;" << endl <<
793 indent() << "if (!method_exists($this, $methodname)) {" << endl;
794 if (binary_inline_) {
795 f_service_ <<
796 indent() << " throw new Exception('Function '.$fname.' not implemented.');" << endl;
797 } else {
798 f_service_ <<
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;
808 f_service_ <<
809 indent() << "}" << endl <<
810 indent() << "$this->$methodname($rseqid, $input, $output);" << endl <<
811 indent() << "return true;" << endl;
812 indent_down();
813 f_service_ <<
814 indent() << "}" << endl <<
815 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);
822 indent_down();
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) {
833 // Open function
834 indent(f_service_) <<
835 "protected function process_" << tfunction->get_name() <<
836 "($seqid, $input, $output) {" << endl;
837 indent_up();
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";
842 f_service_ <<
843 indent() << "$args = new " << argsname << "();" << endl <<
844 indent() << "$args->read($input);" << endl;
845 if (!binary_inline_) {
846 f_service_ <<
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()) {
856 f_service_ <<
857 indent() << "$result = new " << resultname << "();" << endl;
860 // Try block for a function with exceptions
861 if (xceptions.size() > 0) {
862 f_service_ <<
863 indent() << "try {" << endl;
864 indent_up();
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 = ";
876 f_service_ <<
877 "$this->handler_->" << tfunction->get_name() << "(";
878 bool first = true;
879 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
880 if (first) {
881 first = false;
882 } else {
883 f_service_ << ", ";
885 f_service_ << "$args->" << (*f_iter)->get_name();
887 f_service_ << ");" << endl;
889 if (!tfunction->is_async() && xceptions.size() > 0) {
890 indent_down();
891 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
892 f_service_ <<
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()) {
895 indent_up();
896 f_service_ <<
897 indent() << "$result->" << (*x_iter)->get_name() << " = $" << (*x_iter)->get_name() << ";" << endl;
898 indent_down();
899 f_service_ << indent();
902 f_service_ << "}" << endl;
905 // Shortcut out here for async functions
906 if (tfunction->is_async()) {
907 f_service_ <<
908 indent() << "return;" << endl;
909 indent_down();
910 f_service_ <<
911 indent() << "}" << endl;
912 return;
915 // Serialize the request header
916 if (binary_inline_) {
917 f_service_ <<
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;
925 } else {
926 f_service_ <<
927 indent() << "$output->writeMessageBegin('" << tfunction->get_name() << "', TMessageType::REPLY, $seqid);" << endl <<
928 indent() << "$result->write($output);" << endl <<
929 indent() << "$output->getTransport()->flush();" << endl;
932 // Close function
933 indent_down();
934 f_service_ <<
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;
947 f_service_ <<
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);
956 ts->set_name(name);
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) {
990 string extends = "";
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";
996 f_service_ <<
997 "interface " << service_name_ << "If" << extends_if << " {" << endl;
998 indent_up();
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;
1005 indent_down();
1006 f_service_ <<
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";
1020 f_service_ <<
1021 "class " << service_name_ << "Rest" << extends_if << " {" << endl;
1022 indent_up();
1024 if (extends.empty()) {
1025 f_service_ <<
1026 indent() << "protected $impl_;" << endl <<
1027 endl;
1030 f_service_ <<
1031 indent() << "public function __construct($impl) {" << endl <<
1032 indent() << " $this->impl_ = $impl;" << endl <<
1033 indent() << "}" << endl <<
1034 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;
1041 indent_up();
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()) {
1049 f_service_ <<
1050 indent() << "$" << (*a_iter)->get_name() << " = " << cast << "(!empty(" << req << ") && (" << req << " !== 'false'));" << endl;
1051 } else {
1052 f_service_ <<
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()) {
1057 f_service_ <<
1058 indent() << "$" << (*a_iter)->get_name() << " = explode(',', $" << (*a_iter)->get_name() << ");" << endl;
1059 } else if (atype->is_map() || atype->is_list()) {
1060 f_service_ <<
1061 indent() << "$" << (*a_iter)->get_name() << " = json_decode($" << (*a_iter)->get_name() << ", true);" << endl;
1062 } else if (atype->is_set()) {
1063 f_service_ <<
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()) {
1066 f_service_ <<
1067 indent() << "$" << (*a_iter)->get_name() << " = new " << php_namespace(atype->get_program()) << atype->get_name() << "(json_decode($" << (*a_iter)->get_name() << ", true));" << endl;
1070 f_service_ <<
1071 indent() << "return $this->impl_->" << (*f_iter)->get_name() << "(" << argument_list((*f_iter)->get_arglist()) << ");" << endl;
1072 indent_down();
1073 indent(f_service_) <<
1074 "}" << endl <<
1075 endl;
1077 indent_down();
1078 f_service_ <<
1079 "}" << endl << endl;
1082 void t_php_generator::generate_service_client(t_service* tservice) {
1083 if (autoload_) {
1084 // Make output file
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();
1094 f_service_ <<
1095 "$GLOBALS['THRIFT_AUTOLOAD']['" << lowercase(service_name_ + "Client") << "'] = '" << program_name_ << "/" << f_struct << "';" << endl;
1097 } else {
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";
1115 out <<
1116 "class " << service_name_ << "Client" << extends_client << " implements " << service_name_ << "If {" << endl;
1117 indent_up();
1119 // Private members
1120 if (extends.empty()) {
1121 out <<
1122 indent() << "protected $input_ = null;" << endl <<
1123 indent() << "protected $output_ = null;" << endl <<
1124 endl;
1125 out <<
1126 indent() << "protected $seqid_ = 0;" << endl <<
1127 endl;
1130 // Constructor function
1131 out <<
1132 indent() << "public function __construct($input, $output=null) {" << endl;
1133 if (!extends.empty()) {
1134 out <<
1135 indent() << " parent::__construct($input, $output);" << endl;
1136 } else {
1137 out <<
1138 indent() << " $this->input_ = $input;" << endl <<
1139 indent() << " $this->output_ = $output ? $output : $input;" << endl;
1141 out <<
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();
1153 // Open function
1154 indent(out) <<
1155 "public function " << function_signature(*f_iter) << endl;
1156 scope_up(out);
1157 indent(out) <<
1158 "$this->send_" << funname << "(";
1160 bool first = true;
1161 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1162 if (first) {
1163 first = false;
1164 } else {
1165 out << ", ";
1167 out << "$" << (*fld_iter)->get_name();
1169 out << ");" << endl;
1171 if (!(*f_iter)->is_async()) {
1172 out << indent();
1173 if (!(*f_iter)->get_returntype()->is_void()) {
1174 out << "return ";
1176 out <<
1177 "$this->recv_" << funname << "();" << endl;
1179 scope_down(out);
1180 out << endl;
1182 indent(out) <<
1183 "public function send_" << function_signature(*f_iter) << endl;
1184 scope_up(out);
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_) {
1190 out <<
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;
1195 } else {
1196 out <<
1197 indent() << "$this->output_->writeMessageBegin('" << (*f_iter)->get_name() << "', TMessageType::CALL, $this->seqid_);" << endl;
1200 out <<
1201 indent() << "$args = new " << argsname << "();" << endl;
1203 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1204 out <<
1205 indent() << "$args->" << (*fld_iter)->get_name() << " = $" << (*fld_iter)->get_name() << ";" << endl;
1208 // Write to the stream
1209 if (binary_inline_) {
1210 out <<
1211 indent() << "$args->write($buff);" << endl <<
1212 indent() << "$this->output_->write($buff);" << endl <<
1213 indent() << "$this->output_->flush();" << endl;
1214 } else {
1215 out <<
1216 indent() << "$args->write($this->output_);" << endl <<
1217 indent() << "$this->output_->writeMessageEnd();" << endl <<
1218 indent() << "$this->output_->getTransport()->flush();" << endl;
1221 scope_down(out);
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(),
1230 &noargs);
1231 // Open function
1232 out <<
1233 endl <<
1234 indent() << "public function " << function_signature(&recv_function) << endl;
1235 scope_up(out);
1237 out <<
1238 indent() << "$rseqid = 0;" << endl <<
1239 indent() << "$fname = null;" << endl <<
1240 indent() << "$mtype = 0;" << endl <<
1241 endl;
1243 if (binary_inline_) {
1244 t_field ffname(g_type_string, "fname");
1245 t_field fseqid(g_type_i32, "rseqid");
1246 out <<
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);
1254 } else {
1255 out <<
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;
1265 out <<
1266 indent() << "$result = new " << resultname << "();" << endl <<
1267 indent() << "$result->read($this->input_);" << endl;
1269 if (!binary_inline_) {
1270 out <<
1271 indent() << "$this->input_->readMessageEnd();" << endl <<
1272 endl;
1275 // Careful, only return result if not a void function
1276 if (!(*f_iter)->get_returntype()->is_void()) {
1277 out <<
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) {
1287 out <<
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()) {
1295 indent(out) <<
1296 "return;" << endl;
1297 } else {
1298 out <<
1299 indent() << "throw new Exception(\"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
1302 // Close function
1303 scope_down(out);
1304 out << endl;
1309 indent_down();
1310 out <<
1311 "}" << endl << endl;
1315 * Deserializes a field of any type.
1317 void t_php_generator::generate_deserialize_field(ofstream &out,
1318 t_field* tfield,
1319 string prefix,
1320 bool inclass) {
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,
1332 (t_struct*)type,
1333 name);
1334 } else {
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;
1341 indent_up();
1342 string ttype_name;
1343 if (type->is_enum()) {
1344 ttype_name = "I32";
1345 } else {
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;
1353 indent_down();
1354 out << indent() << "} else {" << endl;
1355 indent_up();
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();
1363 switch (tbase) {
1364 case t_base_type::TYPE_VOID:
1365 throw "compiler error: cannot serialize void field in a struct: " +
1366 name;
1367 break;
1368 case t_base_type::TYPE_STRING:
1369 out <<
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;
1376 break;
1377 case t_base_type::TYPE_BOOL:
1378 out <<
1379 indent() << "$" << name << " = unpack('c', " << itrans << "->readAll(1));" << endl <<
1380 indent() << "$" << name << " = (bool)$" << name << "[1];" << endl;
1381 break;
1382 case t_base_type::TYPE_BYTE:
1383 out <<
1384 indent() << "$" << name << " = unpack('c', " << itrans << "->readAll(1));" << endl <<
1385 indent() << "$" << name << " = $" << name << "[1];" << endl;
1386 break;
1387 case t_base_type::TYPE_I16:
1388 out <<
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;
1395 break;
1396 case t_base_type::TYPE_I32:
1397 out <<
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;
1404 break;
1405 case t_base_type::TYPE_I64:
1406 out <<
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;
1415 break;
1416 case t_base_type::TYPE_DOUBLE:
1417 out <<
1418 indent() << "$arr = unpack('d', strrev(" << itrans << "->readAll(8)));" << endl <<
1419 indent() << "$" << name << " = $arr[1];" << endl;
1420 break;
1421 default:
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()) {
1425 out <<
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;
1433 } else {
1435 indent(out) <<
1436 "$xfer += $input->";
1438 if (type->is_base_type()) {
1439 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1440 switch (tbase) {
1441 case t_base_type::TYPE_VOID:
1442 throw "compiler error: cannot serialize void field in a struct: " +
1443 name;
1444 break;
1445 case t_base_type::TYPE_STRING:
1446 out << "readString($" << name << ");";
1447 break;
1448 case t_base_type::TYPE_BOOL:
1449 out << "readBool($" << name << ");";
1450 break;
1451 case t_base_type::TYPE_BYTE:
1452 out << "readByte($" << name << ");";
1453 break;
1454 case t_base_type::TYPE_I16:
1455 out << "readI16($" << name << ");";
1456 break;
1457 case t_base_type::TYPE_I32:
1458 out << "readI32($" << name << ");";
1459 break;
1460 case t_base_type::TYPE_I64:
1461 out << "readI64($" << name << ");";
1462 break;
1463 case t_base_type::TYPE_DOUBLE:
1464 out << "readDouble($" << name << ");";
1465 break;
1466 default:
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 << ");";
1472 out << endl;
1474 out << indent() << "}" << endl;
1475 indent_down();
1476 } else {
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,
1490 t_struct* tstruct,
1491 string prefix) {
1492 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,
1498 t_type* ttype,
1499 string prefix) {
1500 out << indent() << "if (($input instanceof TProtocol::$TBINARYPROTOCOLACCELERATED) && function_exists('thrift_protocol_binary_deserialize'))" << endl;
1501 scope_up(out);
1503 string ttype_name;
1504 t_type* tvaluetype = NULL;
1505 if (ttype->is_map()) {
1506 ttype_name = "MAP";
1507 tvaluetype = reinterpret_cast<t_map*>(ttype)->get_val_type();
1508 } else if (ttype->is_set()) {
1509 ttype_name = "SET";
1510 tvaluetype = reinterpret_cast<t_set*>(ttype)->get_elem_type();
1511 } else if (ttype->is_list()) {
1512 ttype_name = "LST";
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;
1517 } else {
1518 out << indent() << "$" << prefix << " = thrift_protocol_binary_deserialize(TType::" << ttype_name << ", $input);" << endl;
1520 scope_down(out);
1521 out << indent() << "else" << endl;
1522 scope_up(out);
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);
1534 out <<
1535 indent() << "$" << prefix << " = array();" << endl <<
1536 indent() << "$" << size << " = 0;" << endl;
1538 // Declare variables, read header
1539 if (ttype->is_map()) {
1540 out <<
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);
1547 } else {
1548 out <<
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);
1556 } else {
1557 out <<
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);
1566 } else {
1567 out <<
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");
1576 indent(out) <<
1577 "for ($" <<
1578 i << " = 0; $" << i << " < $" << size << "; ++$" << i << ")" << endl;
1580 scope_up(out);
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);
1590 scope_down(out);
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;
1603 scope_down(out);
1608 * Generates code to deserialize a map
1610 void t_php_generator::generate_deserialize_map_element(ofstream &out,
1611 t_map* tmap,
1612 string prefix) {
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);
1618 indent(out) <<
1619 declare_field(&fkey, true, true) << endl;
1620 indent(out) <<
1621 declare_field(&fval, true, true) << endl;
1623 generate_deserialize_field(out, &fkey);
1624 generate_deserialize_field(out, &fval);
1626 indent(out) <<
1627 "$" << prefix << "[$" << key << "] = $" << val << ";" << endl;
1630 void t_php_generator::generate_deserialize_set_element(ofstream &out,
1631 t_set* tset,
1632 string prefix) {
1633 string elem = tmp("elem");
1634 t_field felem(tset->get_elem_type(), elem);
1636 indent(out) <<
1637 "$" << elem << " = null;" << endl;
1639 generate_deserialize_field(out, &felem);
1641 indent(out) <<
1642 "$" << prefix << "[$" << elem << "] = true;" << endl;
1645 void t_php_generator::generate_deserialize_list_element(ofstream &out,
1646 t_list* tlist,
1647 string prefix) {
1648 string elem = tmp("elem");
1649 t_field felem(tlist->get_elem_type(), elem);
1651 indent(out) <<
1652 "$" << elem << " = null;" << endl;
1654 generate_deserialize_field(out, &felem);
1656 indent(out) <<
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,
1668 t_field* tfield,
1669 string prefix) {
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,
1680 (t_struct*)type,
1681 prefix + tfield->get_name());
1682 } else if (type->is_container()) {
1683 generate_serialize_container(out,
1684 type,
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();
1693 switch (tbase) {
1694 case t_base_type::TYPE_VOID:
1695 throw
1696 "compiler error: cannot serialize void field in a struct: " + name;
1697 break;
1698 case t_base_type::TYPE_STRING:
1699 out <<
1700 indent() << "$output .= pack('N', strlen($" << name << "));" << endl <<
1701 indent() << "$output .= $" << name << ";" << endl;
1702 break;
1703 case t_base_type::TYPE_BOOL:
1704 out <<
1705 indent() << "$output .= pack('c', $" << name << " ? 1 : 0);" << endl;
1706 break;
1707 case t_base_type::TYPE_BYTE:
1708 out <<
1709 indent() << "$output .= pack('c', $" << name << ");" << endl;
1710 break;
1711 case t_base_type::TYPE_I16:
1712 out <<
1713 indent() << "$output .= pack('n', $" << name << ");" << endl;
1714 break;
1715 case t_base_type::TYPE_I32:
1716 out <<
1717 indent() << "$output .= pack('N', $" << name << ");" << endl;
1718 break;
1719 case t_base_type::TYPE_I64:
1720 out <<
1721 indent() << "$output .= pack('N2', $" << name << " >> 32, $" << name << " & 0xFFFFFFFF);" << endl;
1722 break;
1723 case t_base_type::TYPE_DOUBLE:
1724 out <<
1725 indent() << "$output .= strrev(pack('d', $" << name << "));" << endl;
1726 break;
1727 default:
1728 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase);
1730 } else if (type->is_enum()) {
1731 out <<
1732 indent() << "$output .= pack('N', $" << name << ");" << endl;
1734 } else {
1736 indent(out) <<
1737 "$xfer += $output->";
1739 if (type->is_base_type()) {
1740 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1741 switch (tbase) {
1742 case t_base_type::TYPE_VOID:
1743 throw
1744 "compiler error: cannot serialize void field in a struct: " + name;
1745 break;
1746 case t_base_type::TYPE_STRING:
1747 out << "writeString($" << name << ");";
1748 break;
1749 case t_base_type::TYPE_BOOL:
1750 out << "writeBool($" << name << ");";
1751 break;
1752 case t_base_type::TYPE_BYTE:
1753 out << "writeByte($" << name << ");";
1754 break;
1755 case t_base_type::TYPE_I16:
1756 out << "writeI16($" << name << ");";
1757 break;
1758 case t_base_type::TYPE_I32:
1759 out << "writeI32($" << name << ");";
1760 break;
1761 case t_base_type::TYPE_I64:
1762 out << "writeI64($" << name << ");";
1763 break;
1764 case t_base_type::TYPE_DOUBLE:
1765 out << "writeDouble($" << name << ");";
1766 break;
1767 default:
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 << ");";
1773 out << endl;
1775 } else {
1776 printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
1777 prefix.c_str(),
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,
1790 t_struct* tstruct,
1791 string prefix) {
1792 indent(out) <<
1793 "$xfer += $" << prefix << "->write($output);" << endl;
1797 * Writes out a container
1799 void t_php_generator::generate_serialize_container(ofstream &out,
1800 t_type* ttype,
1801 string prefix) {
1802 scope_up(out);
1804 if (ttype->is_map()) {
1805 if (binary_inline_) {
1806 out <<
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;
1810 } else {
1811 indent(out) <<
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_) {
1819 out <<
1820 indent() << "$output .= pack('c', " << type_to_enum(((t_set*)ttype)->get_elem_type()) << ");" << endl <<
1821 indent() << "$output .= strrev(pack('l', count($" << prefix << ")));" << endl;
1823 } else {
1824 indent(out) <<
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_) {
1831 out <<
1832 indent() << "$output .= pack('c', " << type_to_enum(((t_list*)ttype)->get_elem_type()) << ");" << endl <<
1833 indent() << "$output .= strrev(pack('l', count($" << prefix << ")));" << endl;
1835 } else {
1836 indent(out) <<
1837 "$output->writeListBegin(" <<
1838 type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
1839 "count($" << prefix << "));" << endl;
1843 scope_up(out);
1845 if (ttype->is_map()) {
1846 string kiter = tmp("kiter");
1847 string viter = tmp("viter");
1848 indent(out) <<
1849 "foreach ($" << prefix << " as " <<
1850 "$" << kiter << " => $" << viter << ")" << endl;
1851 scope_up(out);
1852 generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
1853 scope_down(out);
1854 } else if (ttype->is_set()) {
1855 string iter = tmp("iter");
1856 indent(out) <<
1857 "foreach ($" << prefix << " as $" << iter << " => $true)" << endl;
1858 scope_up(out);
1859 generate_serialize_set_element(out, (t_set*)ttype, iter);
1860 scope_down(out);
1861 } else if (ttype->is_list()) {
1862 string iter = tmp("iter");
1863 indent(out) <<
1864 "foreach ($" << prefix << " as $" << iter << ")" << endl;
1865 scope_up(out);
1866 generate_serialize_list_element(out, (t_list*)ttype, iter);
1867 scope_down(out);
1870 scope_down(out);
1872 if (!binary_inline_) {
1873 if (ttype->is_map()) {
1874 indent(out) <<
1875 "$output->writeMapEnd();" << endl;
1876 } else if (ttype->is_set()) {
1877 indent(out) <<
1878 "$output->writeSetEnd();" << endl;
1879 } else if (ttype->is_list()) {
1880 indent(out) <<
1881 "$output->writeListEnd();" << endl;
1885 scope_down(out);
1889 * Serializes the members of a map.
1892 void t_php_generator::generate_serialize_map_element(ofstream &out,
1893 t_map* tmap,
1894 string kiter,
1895 string viter) {
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,
1907 t_set* tset,
1908 string iter) {
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,
1917 t_list* tlist,
1918 string iter) {
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();
1930 if (init) {
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();
1934 switch (tbase) {
1935 case t_base_type::TYPE_VOID:
1936 break;
1937 case t_base_type::TYPE_STRING:
1938 result += " = ''";
1939 break;
1940 case t_base_type::TYPE_BOOL:
1941 result += " = false";
1942 break;
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:
1947 result += " = 0";
1948 break;
1949 case t_base_type::TYPE_DOUBLE:
1950 result += " = 0.0";
1951 break;
1952 default:
1953 throw "compiler error: no PHP initializer for base type " + t_base_type::t_base_name(tbase);
1955 } else if (type->is_enum()) {
1956 result += " = 0";
1957 } else if (type->is_container()) {
1958 result += " = array()";
1959 } else if (type->is_struct() || type->is_xception()) {
1960 if (obj) {
1961 result += " = new " + php_namespace(type->get_program()) + type->get_name() + "()";
1962 } else {
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,
1977 string prefix) {
1978 return
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) {
1987 string result = "";
1989 const vector<t_field*>& fields = tstruct->get_members();
1990 vector<t_field*>::const_iterator f_iter;
1991 bool first = true;
1992 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1993 if (first) {
1994 first = false;
1995 } else {
1996 result += ", ";
1998 result += "$" + (*f_iter)->get_name();
2000 return result;
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:
2011 return "(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:
2016 return "(int)";
2017 case t_base_type::TYPE_DOUBLE:
2018 return "(double)";
2019 case t_base_type::TYPE_STRING:
2020 return "(string)";
2021 default:
2022 return "";
2024 } else if (type->is_enum()) {
2025 return "(int)";
2027 return "";
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();
2038 switch (tbase) {
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();