]> git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/thrift/compiler/cpp/src/thrift/generate/t_php_generator.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / jaegertracing / thrift / compiler / cpp / src / thrift / generate / t_php_generator.cc
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #include <string>
21 #include <fstream>
22 #include <iostream>
23 #include <vector>
24
25 #include <stdlib.h>
26 #include <sys/stat.h>
27 #include <sstream>
28 #include "thrift/platform.h"
29 #include "thrift/generate/t_oop_generator.h"
30
31 using std::map;
32 using std::ostream;
33 using std::ostringstream;
34 using std::string;
35 using std::stringstream;
36 using std::vector;
37
38 static const string endl = "\n"; // avoid ostream << std::endl flushes
39
40 #define NSGLOBAL (nsglobal_.size() ? nsglobal_ : "")
41 #define NSGLOBAL_A ("\\" + NSGLOBAL)
42 #define NSGLOBAL_B (NSGLOBAL + "\\")
43 #define NSGLOBAL_AB ("\\" + NSGLOBAL + "\\")
44
45 /**
46 * PHP code generator.
47 *
48 */
49 class t_php_generator : public t_oop_generator {
50 public:
51 t_php_generator(t_program* program,
52 const std::map<std::string, std::string>& parsed_options,
53 const std::string& option_string)
54 : t_oop_generator(program) {
55 (void)option_string;
56 std::map<std::string, std::string>::const_iterator iter;
57
58 binary_inline_ = false;
59 rest_ = false;
60 phps_ = false;
61 oop_ = false;
62 validate_ = false;
63 json_serializable_ = false;
64 nsglobal_ = ""; // by default global namespace is empty
65 classmap_ = false;
66 for (iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
67 if (iter->first.compare("inlined") == 0) {
68 binary_inline_ = true;
69 } else if (iter->first.compare("rest") == 0) {
70 rest_ = true;
71 } else if (iter->first.compare("server") == 0) {
72 phps_ = true;
73 } else if (iter->first.compare("oop") == 0) {
74 oop_ = true;
75 } else if (iter->first.compare("validate") == 0) {
76 validate_ = true;
77 } else if (iter->first.compare("json") == 0) {
78 json_serializable_ = true;
79 } else if (iter->first.compare("nsglobal") == 0) {
80 nsglobal_ = iter->second;
81 } else if (iter->first.compare("classmap") == 0) {
82 classmap_ = true;
83 } else if (iter->first.compare("psr4") == 0) {
84 if(classmap_){
85 throw "psr4 and classmap are mutually exclusive.";
86 } else {
87 pwarning(0, "psr4 is default option! needn't add psr4 option!\n");
88 }
89 } else {
90 throw "unknown option php:" + iter->first;
91 }
92 }
93
94 if (oop_ && binary_inline_) {
95 throw "oop and inlined are mutually exclusive.";
96 }
97
98 out_dir_base_ = (binary_inline_ ? "gen-phpi" : "gen-php");
99 escape_['$'] = "\\$";
100 }
101
102 std::string indent_str() const override {
103 return " ";
104 }
105
106 static bool is_valid_namespace(const std::string& sub_namespace);
107
108 /**
109 * Init and close methods
110 */
111
112 void init_generator() override;
113 void close_generator() override;
114
115 /**
116 * Program-level generation functions
117 */
118
119 void generate_typedef(t_typedef* ttypedef) override;
120 void generate_enum(t_enum* tenum) override;
121 void generate_consts(vector<t_const*> consts) override;
122 void generate_struct(t_struct* tstruct) override;
123 void generate_xception(t_struct* txception) override;
124 void generate_service(t_service* tservice) override;
125
126 std::string render_const_value(t_type* type, t_const_value* value);
127
128 /**
129 * Structs!
130 */
131
132 void generate_php_struct(t_struct* tstruct, bool is_exception);
133 void generate_php_struct_definition(std::ostream& out,
134 t_struct* tstruct,
135 bool is_xception = false,
136 bool is_result = false);
137 void generate_php_struct_reader(std::ostream& out, t_struct* tstruct, bool is_result);
138 void generate_php_struct_writer(std::ostream& out, t_struct* tstruct, bool is_result);
139 void generate_php_function_helpers(t_service* tservice, t_function* tfunction);
140 void generate_php_struct_required_validator(ostream& out,
141 t_struct* tstruct,
142 std::string method_name,
143 bool write_mode);
144 void generate_php_struct_read_validator(ostream& out, t_struct* tstruct);
145 void generate_php_struct_write_validator(ostream& out, t_struct* tstruct);
146 void generate_php_struct_json_serialize(ostream& out, t_struct* tstruct, bool is_result);
147 bool needs_php_write_validator(t_struct* tstruct, bool is_result);
148 bool needs_php_read_validator(t_struct* tstruct, bool is_result);
149 int get_php_num_required_fields(const vector<t_field*>& fields, bool write_mode);
150
151 void generate_php_type_spec(std::ostream& out, t_type* t);
152 void generate_php_struct_spec(std::ostream& out, t_struct* tstruct);
153
154 /**
155 * Service-level generation functions
156 */
157
158 void generate_service_helpers(t_service* tservice);
159 void generate_service_interface(t_service* tservice);
160 void generate_service_rest(t_service* tservice);
161 void generate_service_client(t_service* tservice);
162 void generate_service_processor(t_service* tservice);
163 void generate_process_function(std::ostream& out, t_service* tservice, t_function* tfunction);
164 void generate_service_header(t_service* tservice, std::ostream& file);
165 void generate_program_header(std::ostream& file);
166
167 /**
168 * Serialization constructs
169 */
170
171 void generate_deserialize_field(std::ostream& out,
172 t_field* tfield,
173 std::string prefix = "",
174 bool inclass = false);
175
176 void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
177
178 void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
179
180 void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = "");
181
182 void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = "");
183
184 void generate_deserialize_list_element(std::ostream& out,
185 t_list* tlist,
186 std::string prefix = "");
187
188 void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = "");
189
190 void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
191
192 void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
193
194 void generate_serialize_map_element(std::ostream& out,
195 t_map* tmap,
196 std::string kiter,
197 std::string viter);
198
199 void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
200
201 void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);
202
203 void generate_php_doc(std::ostream& out, t_doc* tdoc);
204
205 void generate_php_doc(std::ostream& out, t_field* tfield);
206
207 void generate_php_doc(std::ostream& out, t_function* tfunction);
208
209 void generate_php_docstring_comment(std::ostream& out, string contents);
210
211 /**
212 * Helper rendering functions
213 */
214
215 std::string php_includes();
216 std::string declare_field(t_field* tfield, bool init = false, bool obj = false);
217 std::string function_signature(t_function* tfunction, std::string prefix = "");
218 std::string argument_list(t_struct* tstruct, bool addTypeHints = true);
219 std::string type_to_cast(t_type* ttype);
220 std::string type_to_enum(t_type* ttype);
221 std::string type_to_phpdoc(t_type* ttype);
222
223 bool php_is_scalar(t_type *ttype) {
224 ttype = ttype->get_true_type();
225 if(ttype->is_base_type()) {
226 return true;
227 } else if(ttype->is_enum()) {
228 return true;
229 } else {
230 return false;
231 }
232 }
233
234 std::string php_namespace_base(const t_program* p) {
235 std::string ns = p->get_namespace("php");
236 const char* delimiter = "\\";
237 size_t position = ns.find('.');
238 while (position != string::npos) {
239 ns.replace(position, 1, delimiter);
240 position = ns.find('.', position + 1);
241 }
242 return ns;
243 }
244
245 // general use namespace prefixing: \my\namespace\ or my_namespace_
246 string php_namespace(const t_program* p) {
247 string ns = php_namespace_base(p);
248 return (nsglobal_.size() ? NSGLOBAL_AB : NSGLOBAL_B) + (ns.size() ? (ns + "\\") : "");
249 }
250
251 // return the namespace of a file:
252 // global\ns\sub\ns or global\ns or sub\ns
253 string php_namespace_suffix(const t_program* p) {
254 string ns = php_namespace_base(p);
255
256 return NSGLOBAL
257 + (ns.size() && NSGLOBAL.size() ? "\\" : "")
258 + ns;
259 }
260
261 // add a directory to already existing namespace
262 string php_namespace_directory(string directory, bool end = true) {
263 (void)directory;
264 if (end) {
265 return ";";
266 } else {
267 return "";
268 }
269 }
270
271 // writing an autload identifier into globa;ls: my\namespace\ or my_namespace_
272 string php_namespace_autoload(const t_program* p) {
273 std::string ns = php_namespace_base(p);
274 return (nsglobal_.size() ? NSGLOBAL_B : NSGLOBAL) + (ns.size() ? (ns + "\\") : "");
275 }
276
277 // declaring a type: typename or my_namespace_typename
278 string php_namespace_declaration(t_type* t) { return t->get_name(); }
279
280 std::string php_path(t_program* p) {
281 std::string ns = p->get_namespace("php.path");
282 if (ns.empty()) {
283 return p->get_name();
284 }
285
286 // Transform the java-style namespace into a path.
287 for (char & n : ns) {
288 if (n == '.') {
289 n = '/';
290 }
291 }
292
293 return ns + '/';
294 }
295
296 /**
297 * Transform class_method into ClassMethod
298 *
299 * @param str
300 * @return stirng
301 */
302 string classify(string str) {
303 string classe = "";
304
305 vector<string> x = split(str, '_');
306
307 for (const auto & i : x) {
308 classe = classe + capitalize(i);
309 }
310
311 return classe;
312 }
313
314 /**
315 * Split method
316 * @param s
317 * @param delim
318 * @param elems
319 * @return
320 */
321 vector<string>& split(const string& s, char delim, vector<string>& elems) {
322 stringstream ss(s);
323 string item;
324
325 while (getline(ss, item, delim)) {
326 elems.push_back(item);
327 }
328
329 return elems;
330 }
331
332 vector<string> split(const string& s, char delim) {
333 vector<string> elems;
334
335 return split(s, delim, elems);
336 }
337
338 /**
339 * Capitalize method
340 * @param str
341 * @return
342 */
343 string capitalize(string str) {
344 string::iterator it(str.begin());
345
346 if (it != str.end())
347 str[0] = toupper((unsigned char)str[0]);
348
349 // while(++it != str.end())
350 // {
351 // *it = tolower((unsigned char)*it);
352 // }
353 return str;
354 }
355
356 private:
357 /**
358 * File streams
359 */
360 ofstream_with_content_based_conditional_update f_types_;
361 ofstream_with_content_based_conditional_update f_service_;
362
363 std::string package_dir_;
364 /**
365 * Generate protocol-independent template? Or Binary inline code?
366 */
367 bool binary_inline_;
368
369 /**
370 * Generate a REST handler class
371 */
372 bool rest_;
373
374 /**
375 * Generate stubs for a PHP server
376 */
377 bool phps_;
378
379 /**
380 * Whether to use OOP base class TBase
381 */
382 bool oop_;
383
384 /**
385 * Whether to generate old-style PHP file to use classmap autoloading
386 */
387 bool classmap_;
388
389 /**
390 * Whether to generate validator code
391 */
392 bool validate_;
393
394 /**
395 * Whether to generate JsonSerializable classes
396 */
397 bool json_serializable_;
398
399 /**
400 * Global namespace for PHP 5.3
401 */
402 std::string nsglobal_;
403 };
404
405 bool t_php_generator::is_valid_namespace(const std::string& sub_namespace) {
406 return sub_namespace == "path";
407 }
408
409 /**
410 * Prepares for file generation by opening up the necessary file output
411 * streams.
412 *
413 * @param tprogram The program to generate
414 */
415 void t_php_generator::init_generator() {
416 // Make output directory
417 MKDIR(get_out_dir().c_str());
418
419 // Create Real directory Namespaces
420 vector<string> NSx = split(php_namespace_suffix(get_program()), '\\');
421 package_dir_ = get_out_dir();
422
423 for (const auto & i : NSx) {
424 package_dir_ = package_dir_ + "/" + i + "/";
425 MKDIR(package_dir_.c_str());
426 }
427
428 // Prepare output file for all the types in classmap mode
429 if (classmap_) {
430 // Make output file
431 string f_types_name = package_dir_ + "Types.php";
432 f_types_.open(f_types_name.c_str());
433 generate_program_header(f_types_);
434 }
435 }
436
437 /**
438 * Prints standard php includes
439 */
440 string t_php_generator::php_includes() {
441 string includes = "use Thrift\\Base\\TBase;\n"
442 "use Thrift\\Type\\TType;\n"
443 "use Thrift\\Type\\TMessageType;\n"
444 "use Thrift\\Exception\\TException;\n"
445 "use Thrift\\Exception\\TProtocolException;\n"
446 "use Thrift\\Protocol\\TProtocol;\n"
447 "use Thrift\\Protocol\\TBinaryProtocolAccelerated;\n"
448 "use Thrift\\Exception\\TApplicationException;\n";
449
450 if (json_serializable_) {
451 includes += "use JsonSerializable;\n"
452 "use stdClass;\n";
453 }
454
455 return includes;
456 }
457
458 /**
459 * Close up (or down) some filez.
460 */
461 void t_php_generator::close_generator() {
462 if (classmap_) {
463 // Close types file
464 f_types_.close();
465 }
466 }
467
468 /**
469 * Generates a typedef. This is not done in PHP, types are all implicit.
470 *
471 * @param ttypedef The type definition
472 */
473 void t_php_generator::generate_typedef(t_typedef* ttypedef) {
474 (void)ttypedef;
475 }
476
477 /**
478 * Generates service header contains namespace suffix and includes inside file specified
479 */
480 void t_php_generator::generate_service_header(t_service* tservice, std::ostream& file) {
481 file << "<?php" << endl;
482 if (!php_namespace_suffix(tservice->get_program()).empty()) {
483 file << "namespace " << php_namespace_suffix(tservice->get_program()) << ";" << endl
484 << endl;
485 }
486 file << autogen_comment() << php_includes();
487
488 file << endl;
489 }
490
491 /**
492 * Generates program header contains namespace suffix and includes inside file specified
493 */
494 void t_php_generator::generate_program_header(std::ostream& file) {
495 file << "<?php" << endl;
496 if (!php_namespace_suffix(get_program()).empty()) {
497 file << "namespace " << php_namespace_suffix(get_program()) << ";" << endl
498 << endl;
499 }
500 file << autogen_comment() << php_includes();
501
502 file << endl;
503 }
504
505 /**
506 * Generates code for an enumerated type. Since define is expensive to lookup
507 * in PHP, we use a global array for this.
508 *
509 * @param tenum The enumeration
510 */
511 void t_php_generator::generate_enum(t_enum* tenum) {
512 ofstream_with_content_based_conditional_update& f_enum = f_types_;
513 if (!classmap_) {
514 string f_enum_name = package_dir_ + tenum->get_name() + ".php";
515 f_enum.open(f_enum_name.c_str());
516 generate_program_header(f_enum);
517 }
518
519 vector<t_enum_value*> constants = tenum->get_constants();
520 vector<t_enum_value*>::iterator c_iter;
521
522 // We're also doing it this way to see how it performs. It's more legible
523 // code but you can't do things like an 'extract' on it, which is a bit of
524 // a downer.
525 generate_php_doc(f_enum, tenum);
526 f_enum << "final class " << tenum->get_name() << endl
527 << "{" << endl;
528 indent_up();
529
530 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
531 int value = (*c_iter)->get_value();
532 generate_php_doc(f_enum, *c_iter);
533 indent(f_enum) << "const " << (*c_iter)->get_name() << " = " << value << ";" << endl
534 << endl;
535 }
536
537 indent(f_enum) << "static public $__names = array(" << endl;
538
539 indent_up();
540 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
541 int value = (*c_iter)->get_value();
542 indent(f_enum) << value << " => '" << (*c_iter)->get_name() << "'," << endl;
543 }
544 indent_down();
545 indent(f_enum) << ");" << endl;
546
547 indent_down();
548
549 f_enum << "}" << endl << endl;
550 if (!classmap_) {
551 f_enum.close();
552 }
553 }
554
555 /**
556 * Generate constant class
557 *
558 * Override the one from t_generator
559 */
560 void t_php_generator::generate_consts(vector<t_const*> consts) {
561 vector<t_const*>::iterator c_iter;
562
563 // Create class only if needed
564 if (consts.size() > 0) {
565
566 ofstream_with_content_based_conditional_update& f_consts = f_types_;
567 if (!classmap_) {
568 string f_consts_name = package_dir_ + "Constant.php";
569 f_consts.open(f_consts_name.c_str());
570 generate_program_header(f_consts);
571 }
572 f_consts << "final class Constant extends \\Thrift\\Type\\TConstant"<< endl
573 << "{" << endl;
574
575 indent_up();
576
577 // Create static property
578 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
579 string name = (*c_iter)->get_name();
580
581 indent(f_consts) << "static protected $" << name << ";" << endl;
582 }
583
584 // Create init function
585 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
586 string name = (*c_iter)->get_name();
587
588 f_consts << endl;
589
590 f_consts << indent() << "protected static function init_" << name << "()" <<endl
591 << indent() << "{" << endl;
592 indent_up();
593
594 indent(f_consts) << "return ";
595 generate_php_doc(f_consts, *c_iter);
596 f_consts << render_const_value((*c_iter)->get_type(), (*c_iter)->get_value());
597 f_consts << ";" << endl;
598
599 indent_down();
600 indent(f_consts) << "}" << endl;
601 }
602
603 indent_down();
604 f_consts << "}" << endl;
605 if (!classmap_) {
606 f_consts.close();
607 }
608 }
609 }
610
611 /**
612 * Prints the value of a constant with the given type. Note that type checking
613 * is NOT performed in this function as it is always run beforehand using the
614 * validate_types method in main.cc
615 */
616 string t_php_generator::render_const_value(t_type* type, t_const_value* value) {
617 std::ostringstream out;
618 type = get_true_type(type);
619 if (type->is_base_type()) {
620 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
621 switch (tbase) {
622 case t_base_type::TYPE_STRING:
623 out << '"' << get_escaped_string(value) << '"';
624 break;
625 case t_base_type::TYPE_BOOL:
626 out << (value->get_integer() > 0 ? "true" : "false");
627 break;
628 case t_base_type::TYPE_I8:
629 case t_base_type::TYPE_I16:
630 case t_base_type::TYPE_I32:
631 case t_base_type::TYPE_I64:
632 out << value->get_integer();
633 break;
634 case t_base_type::TYPE_DOUBLE:
635 if (value->get_type() == t_const_value::CV_INTEGER) {
636 out << value->get_integer();
637 } else {
638 out << value->get_double();
639 }
640 break;
641 default:
642 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
643 }
644 } else if (type->is_enum()) {
645 indent(out) << value->get_integer();
646 } else if (type->is_struct() || type->is_xception()) {
647 out << "new " << php_namespace(type->get_program()) << type->get_name() << "(array(" << endl;
648 indent_up();
649 const vector<t_field*>& fields = ((t_struct*)type)->get_members();
650 vector<t_field*>::const_iterator f_iter;
651 const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
652 map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
653 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
654 t_type* field_type = NULL;
655 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
656 if ((*f_iter)->get_name() == v_iter->first->get_string()) {
657 field_type = (*f_iter)->get_type();
658 }
659 }
660 if (field_type == NULL) {
661 throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
662 }
663 out << indent();
664 out << render_const_value(g_type_string, v_iter->first);
665 out << " => ";
666 out << render_const_value(field_type, v_iter->second);
667 out << "," << endl;
668 }
669 indent_down();
670 indent(out) << "))";
671 } else if (type->is_map()) {
672 t_type* ktype = ((t_map*)type)->get_key_type();
673 t_type* vtype = ((t_map*)type)->get_val_type();
674 out << "array(" << endl;
675 indent_up();
676 const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
677 map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
678 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
679 out << indent();
680 out << render_const_value(ktype, v_iter->first);
681 out << " => ";
682 out << render_const_value(vtype, v_iter->second);
683 out << "," << endl;
684 }
685 indent_down();
686 indent(out) << ")";
687 } else if (type->is_list() || type->is_set()) {
688 t_type* etype;
689 if (type->is_list()) {
690 etype = ((t_list*)type)->get_elem_type();
691 } else {
692 etype = ((t_set*)type)->get_elem_type();
693 }
694 out << "array(" << endl;
695 indent_up();
696 const vector<t_const_value*>& val = value->get_list();
697 vector<t_const_value*>::const_iterator v_iter;
698 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
699 out << indent();
700 out << render_const_value(etype, *v_iter);
701 if (type->is_set()) {
702 out << " => true";
703 }
704 out << "," << endl;
705 }
706 indent_down();
707 indent(out) << ")";
708 }
709 return out.str();
710 }
711
712 /**
713 * Make a struct
714 */
715 void t_php_generator::generate_struct(t_struct* tstruct) {
716 generate_php_struct(tstruct, false);
717 }
718
719 /**
720 * Generates a struct definition for a thrift exception. Basically the same
721 * as a struct but extends the Exception class.
722 *
723 * @param txception The struct definition
724 */
725 void t_php_generator::generate_xception(t_struct* txception) {
726 generate_php_struct(txception, true);
727 }
728
729 /**
730 * Structs can be normal or exceptions.
731 */
732 void t_php_generator::generate_php_struct(t_struct* tstruct, bool is_exception) {
733 ofstream_with_content_based_conditional_update& f_struct = f_types_;
734 if (!classmap_) {
735 string f_struct_name = package_dir_ + tstruct->get_name() + ".php";
736 f_struct.open(f_struct_name.c_str());
737 generate_program_header(f_struct);
738 }
739 generate_php_struct_definition(f_struct, tstruct, is_exception);
740 if (!classmap_) {
741 f_struct.close();
742 }
743 }
744
745 void t_php_generator::generate_php_type_spec(ostream& out, t_type* t) {
746 t = get_true_type(t);
747 indent(out) << "'type' => " << type_to_enum(t) << "," << endl;
748
749 if (t->is_base_type() || t->is_enum()) {
750 // Noop, type is all we need
751 } else if (t->is_struct() || t->is_xception()) {
752 indent(out) << "'class' => '" << php_namespace(t->get_program()) << t->get_name() << "',"
753 << endl;
754 } else if (t->is_map()) {
755 t_type* ktype = get_true_type(((t_map*)t)->get_key_type());
756 t_type* vtype = get_true_type(((t_map*)t)->get_val_type());
757 indent(out) << "'ktype' => " << type_to_enum(ktype) << "," << endl;
758 indent(out) << "'vtype' => " << type_to_enum(vtype) << "," << endl;
759 indent(out) << "'key' => array(" << endl;
760 indent_up();
761 generate_php_type_spec(out, ktype);
762 indent_down();
763 indent(out) << ")," << endl;
764 indent(out) << "'val' => array(" << endl;
765 indent_up();
766 generate_php_type_spec(out, vtype);
767 indent(out) << ")," << endl;
768 indent_down();
769 } else if (t->is_list() || t->is_set()) {
770 t_type* etype;
771 if (t->is_list()) {
772 etype = get_true_type(((t_list*)t)->get_elem_type());
773 } else {
774 etype = get_true_type(((t_set*)t)->get_elem_type());
775 }
776 indent(out) << "'etype' => " << type_to_enum(etype) << "," << endl;
777 indent(out) << "'elem' => array(" << endl;
778 indent_up();
779 generate_php_type_spec(out, etype);
780 indent(out) << ")," << endl;
781 indent_down();
782 } else {
783 throw "compiler error: no type for php struct spec field";
784 }
785 }
786
787 /**
788 * Generates the struct specification structure, which fully qualifies enough
789 * type information to generalize serialization routines.
790 */
791 void t_php_generator::generate_php_struct_spec(ostream& out, t_struct* tstruct) {
792 indent(out) << "static public $_TSPEC = array(" << endl;
793 indent_up();
794
795 const vector<t_field*>& members = tstruct->get_members();
796 vector<t_field*>::const_iterator m_iter;
797 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
798 t_type* t = get_true_type((*m_iter)->get_type());
799 indent(out) << (*m_iter)->get_key() << " => array(" << endl;
800 indent_up();
801 out << indent() << "'var' => '" << (*m_iter)->get_name() << "'," << endl;
802 out << indent() << "'isRequired' => " << ((*m_iter)->get_req() == t_field::T_REQUIRED ? "true" : "false") << "," << endl;
803 generate_php_type_spec(out, t);
804 indent_down();
805 indent(out) << ")," << endl;
806 }
807
808 indent_down();
809 indent(out) << ");" << endl << endl;
810 }
811
812 /**
813 * Generates a struct definition for a thrift data type. This is nothing in PHP
814 * where the objects are all just associative arrays (unless of course we
815 * decide to start using objects for them...)
816 *
817 * @param tstruct The struct definition
818 */
819 void t_php_generator::generate_php_struct_definition(ostream& out,
820 t_struct* tstruct,
821 bool is_exception,
822 bool is_result) {
823 const vector<t_field*>& members = tstruct->get_members();
824 vector<t_field*>::const_iterator m_iter;
825
826 generate_php_doc(out, tstruct);
827 out << "class " << php_namespace_declaration(tstruct);
828 if (is_exception) {
829 out << " extends "
830 << "TException";
831 } else if (oop_) {
832 out << " extends "
833 << "TBase";
834 }
835 if (json_serializable_) {
836 out << " implements JsonSerializable";
837 }
838 out << endl
839 << "{" << endl;
840 indent_up();
841
842 out << indent() << "static public $isValidate = " << (validate_ ? "true" : "false") << ";" << endl << endl;
843
844 generate_php_struct_spec(out, tstruct);
845
846 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
847 string dval = "null";
848 t_type* t = get_true_type((*m_iter)->get_type());
849 if ((*m_iter)->get_value() != NULL && !(t->is_struct() || t->is_xception())) {
850 dval = render_const_value((*m_iter)->get_type(), (*m_iter)->get_value());
851 }
852 generate_php_doc(out, *m_iter);
853 indent(out) << "public $" << (*m_iter)->get_name() << " = " << dval << ";" << endl;
854 }
855
856 out << endl;
857
858 // Generate constructor from array
859 string param = (members.size() > 0) ? "$vals = null" : "";
860 out << indent() << "public function __construct(" << param << ")"<< endl
861 << indent() << "{" << endl;
862 indent_up();
863
864 if (members.size() > 0) {
865 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
866 t_type* t = get_true_type((*m_iter)->get_type());
867 if ((*m_iter)->get_value() != NULL && (t->is_struct() || t->is_xception())) {
868 indent(out) << "$this->" << (*m_iter)->get_name() << " = "
869 << render_const_value(t, (*m_iter)->get_value()) << ";" << endl;
870 }
871 }
872 out << indent() << "if (is_array($vals)) {" << endl;
873 indent_up();
874 if (oop_) {
875 out << indent() << "parent::__construct(self::$_TSPEC, $vals);" << endl;
876 } else {
877 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
878 out << indent() << "if (isset($vals['" << (*m_iter)->get_name() << "'])) {" << endl;
879
880 indent_up();
881 out << indent() << "$this->" << (*m_iter)->get_name() << " = $vals['"
882 << (*m_iter)->get_name() << "'];" << endl;
883
884 indent_down();
885 out << indent() << "}" << endl;
886 }
887 }
888 indent_down();
889 out << indent() << "}" << endl;
890 }
891 scope_down(out);
892 out << endl;
893
894 out << indent() << "public function getName()" << endl
895 << indent() << "{" << endl;
896
897 indent_up();
898 out << indent() << "return '" << tstruct->get_name() << "';" << endl;
899
900 indent_down();
901 out << indent() << "}" << endl << endl;
902
903 out << endl;
904 generate_php_struct_reader(out, tstruct, is_result);
905 out << endl;
906 generate_php_struct_writer(out, tstruct, is_result);
907 if (needs_php_read_validator(tstruct, is_result)) {
908 out << endl;
909 generate_php_struct_read_validator(out, tstruct);
910 }
911 if (needs_php_write_validator(tstruct, is_result)) {
912 out << endl;
913 generate_php_struct_write_validator(out, tstruct);
914 }
915 if (json_serializable_) {
916 out << endl;
917 generate_php_struct_json_serialize(out, tstruct, is_result);
918 }
919
920 indent_down();
921 out << indent() << "}" << endl;
922 }
923
924 /**
925 * Generates the read() method for a struct
926 */
927 void t_php_generator::generate_php_struct_reader(ostream& out, t_struct* tstruct, bool is_result) {
928 const vector<t_field*>& fields = tstruct->get_members();
929 vector<t_field*>::const_iterator f_iter;
930
931 indent(out) << "public function read($input)" << endl;
932 scope_up(out);
933
934 if (oop_) {
935 if (needs_php_read_validator(tstruct, is_result)) {
936 indent(out) << "$tmp = $this->_read('" << tstruct->get_name() << "', self::$_TSPEC, $input);"
937 << endl;
938 indent(out) << "$this->_validateForRead();" << endl;
939 indent(out) << "return $tmp;" << endl;
940 } else {
941 indent(out) << "return $this->_read('" << tstruct->get_name() << "', self::$_TSPEC, $input);"
942 << endl;
943 }
944 scope_down(out);
945 out << endl;
946 return;
947 }
948
949 out << indent() << "$xfer = 0;" << endl << indent() << "$fname = null;" << endl << indent()
950 << "$ftype = 0;" << endl << indent() << "$fid = 0;" << endl;
951
952 // Declare stack tmp variables
953 if (!binary_inline_) {
954 indent(out) << "$xfer += $input->readStructBegin($fname);" << endl;
955 }
956
957 // Loop over reading in fields
958 indent(out) << "while (true) {" << endl;
959
960 indent_up();
961
962 // Read beginning field marker
963 if (binary_inline_) {
964 t_field fftype(g_type_i8, "ftype");
965 t_field ffid(g_type_i16, "fid");
966 generate_deserialize_field(out, &fftype);
967 out << indent() << "if ($ftype == "
968 << "TType::STOP) {" << endl << indent() << " break;" << endl << indent() << "}" << endl;
969 generate_deserialize_field(out, &ffid);
970 } else {
971 indent(out) << "$xfer += $input->readFieldBegin($fname, $ftype, $fid);" << endl;
972 // Check for field STOP marker and break
973 indent(out) << "if ($ftype == "
974 << "TType::STOP) {" << endl;
975 indent_up();
976 indent(out) << "break;" << endl;
977 indent_down();
978 indent(out) << "}" << endl;
979 }
980
981 // Switch statement on the field we are reading
982 indent(out) << "switch ($fid) {" << endl;
983
984 indent_up();
985
986 // Generate deserialization code for known cases
987 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
988 indent(out) << "case " << (*f_iter)->get_key() << ":" << endl;
989 indent_up();
990 indent(out) << "if ($ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
991 indent_up();
992 generate_deserialize_field(out, *f_iter, "this->");
993 indent_down();
994 out << indent() << "} else {" << endl;
995
996 indent_up();
997 if (binary_inline_) {
998 indent(out) << "$xfer += TProtocol::skipBinary($input, $ftype);" << endl;
999 } else {
1000 indent(out) << "$xfer += $input->skip($ftype);" << endl;
1001 }
1002
1003 indent_down();
1004 out << indent() << "}" << endl << indent() << "break;" << endl;
1005 indent_down();
1006 }
1007
1008 // In the default case we skip the field
1009 indent(out) << "default:" << endl;
1010
1011 indent_up();
1012 if (binary_inline_) {
1013 indent(out) << "$xfer += "
1014 << "TProtocol::skipBinary($input, $ftype);" << endl;
1015 } else {
1016 indent(out) << "$xfer += $input->skip($ftype);" << endl;
1017 }
1018 indent(out) << "break;" << endl;
1019 indent_down();
1020
1021 scope_down(out);
1022
1023 if (!binary_inline_) {
1024 // Read field end marker
1025 indent(out) << "$xfer += $input->readFieldEnd();" << endl;
1026 }
1027
1028 scope_down(out);
1029
1030 if (!binary_inline_) {
1031 indent(out) << "$xfer += $input->readStructEnd();" << endl;
1032 }
1033
1034 if (needs_php_read_validator(tstruct, is_result)) {
1035 indent(out) << "$this->_validateForRead();" << endl;
1036 }
1037
1038 indent(out) << "return $xfer;" << endl;
1039
1040 indent_down();
1041 out << indent() << "}" << endl;
1042 }
1043
1044 /**
1045 * Generates the write() method for a struct
1046 */
1047 void t_php_generator::generate_php_struct_writer(ostream& out, t_struct* tstruct, bool is_result) {
1048 string name = tstruct->get_name();
1049 const vector<t_field*>& fields = tstruct->get_sorted_members();
1050 vector<t_field*>::const_iterator f_iter;
1051
1052 if (binary_inline_) {
1053 indent(out) << "public function write(&$output)" << endl;
1054 } else {
1055 indent(out) << "public function write($output)" << endl;
1056 }
1057 indent(out) << "{" << endl;
1058 indent_up();
1059
1060 if (needs_php_write_validator(tstruct, is_result)) {
1061 indent(out) << "$this->_validateForWrite();" << endl;
1062 }
1063
1064 if (oop_) {
1065 indent(out) << "return $this->_write('" << tstruct->get_name() << "', self::$_TSPEC, $output);"
1066 << endl;
1067 scope_down(out);
1068 out << endl;
1069 return;
1070 }
1071
1072 indent(out) << "$xfer = 0;" << endl;
1073
1074 if (!binary_inline_) {
1075 indent(out) << "$xfer += $output->writeStructBegin('" << name << "');" << endl;
1076 }
1077
1078 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1079 out << indent() << "if ($this->" << (*f_iter)->get_name() << " !== null) {" << endl;
1080 indent_up();
1081
1082 t_type* type = get_true_type((*f_iter)->get_type());
1083 string expect;
1084 if (type->is_container()) {
1085 expect = "array";
1086 } else if (type->is_struct()) {
1087 expect = "object";
1088 }
1089 if (!expect.empty()) {
1090 out << indent() << "if (!is_" << expect << "($this->" << (*f_iter)->get_name() << ")) {"
1091 << endl;
1092 indent_up();
1093 out << indent() << "throw new "
1094 << "TProtocolException('Bad type in structure.', "
1095 << "TProtocolException::INVALID_DATA);" << endl;
1096 scope_down(out);
1097 }
1098
1099 // Write field header
1100 if (binary_inline_) {
1101 out << indent() << "$output .= pack('c', " << type_to_enum((*f_iter)->get_type()) << ");"
1102 << endl << indent() << "$output .= pack('n', " << (*f_iter)->get_key() << ");" << endl;
1103 } else {
1104 indent(out) << "$xfer += $output->writeFieldBegin("
1105 << "'" << (*f_iter)->get_name() << "', " << type_to_enum((*f_iter)->get_type())
1106 << ", " << (*f_iter)->get_key() << ");" << endl;
1107 }
1108
1109 // Write field contents
1110 generate_serialize_field(out, *f_iter, "this->");
1111
1112 // Write field closer
1113 if (!binary_inline_) {
1114 indent(out) << "$xfer += $output->writeFieldEnd();" << endl;
1115 }
1116
1117 indent_down();
1118 indent(out) << "}" << endl;
1119 }
1120
1121 if (binary_inline_) {
1122 out << indent() << "$output .= pack('c', "
1123 << "TType::STOP);" << endl;
1124 } else {
1125 out << indent() << "$xfer += $output->writeFieldStop();" << endl << indent()
1126 << "$xfer += $output->writeStructEnd();" << endl;
1127 }
1128
1129 out << indent() << "return $xfer;" << endl;
1130
1131 indent_down();
1132 out << indent() << "}" << endl;
1133 }
1134
1135 void t_php_generator::generate_php_struct_read_validator(ostream& out, t_struct* tstruct) {
1136 generate_php_struct_required_validator(out, tstruct, "_validateForRead", false);
1137 }
1138
1139 void t_php_generator::generate_php_struct_write_validator(ostream& out, t_struct* tstruct) {
1140 generate_php_struct_required_validator(out, tstruct, "_validateForWrite", true);
1141 }
1142
1143 void t_php_generator::generate_php_struct_required_validator(ostream& out,
1144 t_struct* tstruct,
1145 std::string method_name,
1146 bool write_mode) {
1147 indent(out) << "private function " << method_name << "() {" << endl;
1148 indent_up();
1149
1150 const vector<t_field*>& fields = tstruct->get_members();
1151
1152 if (fields.size() > 0) {
1153 vector<t_field*>::const_iterator f_iter;
1154
1155 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1156 t_field* field = (*f_iter);
1157 if (field->get_req() == t_field::T_REQUIRED
1158 || (field->get_req() == t_field::T_OPT_IN_REQ_OUT && write_mode)) {
1159 indent(out) << "if ($this->" << field->get_name() << " === null) {" << endl;
1160 indent_up();
1161 indent(out) << "throw new TProtocolException('Required field " << tstruct->get_name() << "."
1162 << field->get_name() << " is unset!');" << endl;
1163 indent_down();
1164 indent(out) << "}" << endl;
1165 }
1166 }
1167 }
1168
1169 indent_down();
1170 indent(out) << "}" << endl;
1171 }
1172
1173 void t_php_generator::generate_php_struct_json_serialize(ostream& out,
1174 t_struct* tstruct,
1175 bool is_result) {
1176 indent(out) << "public function jsonSerialize() {" << endl;
1177 indent_up();
1178
1179 if (needs_php_write_validator(tstruct, is_result)) {
1180 indent(out) << "$this->_validateForWrite();" << endl;
1181 }
1182
1183 indent(out) << "$json = new stdClass;" << endl;
1184
1185 const vector<t_field*>& fields = tstruct->get_members();
1186
1187 if (fields.size() > 0) {
1188 vector<t_field*>::const_iterator f_iter;
1189 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1190 t_field* field = (*f_iter);
1191 t_type* type = field->get_type();
1192 const string& name = field->get_name();
1193 if (type->is_map()) {
1194 t_type* key_type = ((t_map*)type)->get_key_type();
1195 if (!(key_type->is_base_type() || key_type->is_enum())) {
1196 // JSON object keys must be strings. PHP's json_encode()
1197 // function will convert any scalar key to strings, but
1198 // we skip thrift maps with non-scalar keys.
1199 continue;
1200 }
1201 }
1202 indent(out) << "if ($this->" << name << " !== null) {" << endl;
1203 indent_up();
1204 indent(out) << "$json->" << name << " = ";
1205 if (type->is_map()) {
1206 out << "(object)";
1207 } else {
1208 out << type_to_cast(type);
1209 }
1210 out << "$this->" << name << ";" << endl;
1211 indent_down();
1212 indent(out) << "}" << endl;
1213 }
1214 }
1215
1216 indent(out) << "return $json;" << endl;
1217 indent_down();
1218
1219 indent(out) << "}" << endl;
1220 }
1221
1222 int t_php_generator::get_php_num_required_fields(const vector<t_field*>& fields, bool write_mode) {
1223 int num_req = 0;
1224
1225 if (fields.size() > 0) {
1226 vector<t_field*>::const_iterator f_iter;
1227 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1228 if ((*f_iter)->get_req() == t_field::T_REQUIRED
1229 || ((*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT && write_mode)) {
1230 ++num_req;
1231 }
1232 }
1233 }
1234 return num_req;
1235 }
1236
1237 bool t_php_generator::needs_php_write_validator(t_struct* tstruct, bool is_result) {
1238 return (validate_ && !is_result && !tstruct->is_union()
1239 && get_php_num_required_fields(tstruct->get_members(), true) > 0);
1240 }
1241
1242 bool t_php_generator::needs_php_read_validator(t_struct* tstruct, bool is_result) {
1243 return (validate_ && !is_result
1244 && (get_php_num_required_fields(tstruct->get_members(), false) > 0));
1245 }
1246
1247 /**
1248 * Generates a thrift service.
1249 *
1250 * @param tservice The service definition
1251 */
1252 void t_php_generator::generate_service(t_service* tservice) {
1253 if(classmap_) {
1254 string f_service_name = package_dir_ + service_name_ + ".php";
1255 f_service_.open(f_service_name.c_str());
1256 generate_service_header(tservice, f_service_);
1257 }
1258
1259 // Generate the three main parts of the service (well, two for now in PHP)
1260 generate_service_interface(tservice);
1261 if (rest_) {
1262 generate_service_rest(tservice);
1263 }
1264 generate_service_client(tservice);
1265 generate_service_helpers(tservice);
1266 if (phps_) {
1267 generate_service_processor(tservice);
1268 }
1269
1270 if(classmap_) {
1271 // Close service file
1272 f_service_ << endl;
1273 f_service_.close();
1274 }
1275 }
1276
1277 /**
1278 * Generates a service server definition.
1279 *
1280 * @param tservice The service to generate a server for.
1281 */
1282 void t_php_generator::generate_service_processor(t_service* tservice) {
1283 ofstream_with_content_based_conditional_update& f_service_processor = f_service_;
1284 if (!classmap_) {
1285 string f_service_processor_name = package_dir_ + service_name_ + "Processor.php";
1286 f_service_processor.open(f_service_processor_name.c_str());
1287 generate_service_header(tservice, f_service_processor);
1288 }
1289
1290 // Generate the dispatch methods
1291 vector<t_function*> functions = tservice->get_functions();
1292 vector<t_function*>::iterator f_iter;
1293
1294 string extends = "";
1295 string extends_processor = "";
1296 if (tservice->get_extends() != NULL) {
1297 extends = tservice->get_extends()->get_name();
1298 extends_processor = " extends " + php_namespace(tservice->get_extends()->get_program())
1299 + extends + "Processor";
1300 }
1301
1302 // Generate the header portion
1303 f_service_processor << "class " << service_name_ << "Processor" << extends_processor << endl
1304 << "{" << endl;
1305 indent_up();
1306
1307 if (extends.empty()) {
1308 f_service_processor << indent() << "protected $handler_ = null;" << endl;
1309 }
1310
1311 f_service_processor << indent() << "public function __construct($handler)"<< endl
1312 << indent() << "{" << endl;
1313
1314 indent_up();
1315 if (extends.empty()) {
1316 f_service_processor << indent() << "$this->handler_ = $handler;" << endl;
1317 } else {
1318 f_service_processor << indent() << "parent::__construct($handler);" << endl;
1319 }
1320
1321 indent_down();
1322 f_service_processor << indent() << "}" << endl << endl;
1323
1324 // Generate the server implementation
1325 f_service_processor << indent() << "public function process($input, $output)" << endl
1326 << indent() << "{" << endl;
1327 indent_up();
1328
1329 f_service_processor << indent() << "$rseqid = 0;" << endl << indent() << "$fname = null;" << endl
1330 << indent() << "$mtype = 0;" << endl << endl;
1331
1332 if (binary_inline_) {
1333 t_field ffname(g_type_string, "fname");
1334 t_field fmtype(g_type_i8, "mtype");
1335 t_field fseqid(g_type_i32, "rseqid");
1336 generate_deserialize_field(f_service_processor, &ffname, "", true);
1337 generate_deserialize_field(f_service_processor, &fmtype, "", true);
1338 generate_deserialize_field(f_service_processor, &fseqid, "", true);
1339 } else {
1340 f_service_processor << indent() << "$input->readMessageBegin($fname, $mtype, $rseqid);" << endl;
1341 }
1342
1343 // HOT: check for method implementation
1344 f_service_processor << indent() << "$methodname = 'process_'.$fname;" << endl
1345 << indent() << "if (!method_exists($this, $methodname)) {" << endl;
1346
1347 indent_up();
1348 if (binary_inline_) {
1349 f_service_processor << indent() << "throw new \\Exception('Function '.$fname.' not implemented.');" << endl;
1350 } else {
1351 f_service_processor << indent() << " $input->skip("
1352 << "TType::STRUCT);" << endl << indent() << " $input->readMessageEnd();" << endl
1353 << indent() << " $x = new "
1354 << "TApplicationException('Function '.$fname.' not implemented.', "
1355 << "TApplicationException::UNKNOWN_METHOD);" << endl << indent()
1356 << " $output->writeMessageBegin($fname, "
1357 << "TMessageType::EXCEPTION, $rseqid);" << endl << indent()
1358 << " $x->write($output);" << endl << indent() << " $output->writeMessageEnd();"
1359 << endl << indent() << " $output->getTransport()->flush();" << endl << indent()
1360 << " return;" << endl;
1361 }
1362
1363 indent_down();
1364 f_service_processor << indent() << "}" << endl
1365 << indent() << "$this->$methodname($rseqid, $input, $output);" << endl
1366 << indent() << "return true;" << endl;
1367
1368 indent_down();
1369 f_service_processor << indent() << "}" << endl << endl;
1370
1371 // Generate the process subfunctions
1372 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1373 generate_process_function(f_service_processor, tservice, *f_iter);
1374 }
1375
1376 indent_down();
1377 f_service_processor << "}" << endl;
1378
1379 if (!classmap_) {
1380 f_service_processor.close();
1381 }
1382 }
1383
1384 /**
1385 * Generates a process function definition.
1386 *
1387 * @param tfunction The function to write a dispatcher for
1388 */
1389 void t_php_generator::generate_process_function(std::ostream& out, t_service* tservice, t_function* tfunction) {
1390 // Open function
1391 out << indent() << "protected function process_" << tfunction->get_name() << "($seqid, $input, $output)" << endl
1392 << indent() << "{" << endl;
1393 indent_up();
1394
1395 string argsname = php_namespace(tservice->get_program()) + service_name_ + "_"
1396 + tfunction->get_name() + "_args";
1397 string resultname = php_namespace(tservice->get_program()) + service_name_ + "_"
1398 + tfunction->get_name() + "_result";
1399
1400 out << indent() << "$bin_accel = ($input instanceof "
1401 << "TBinaryProtocolAccelerated) && function_exists('thrift_protocol_read_binary_after_message_begin');"
1402 << endl;
1403 out << indent() << "if ($bin_accel) {" << endl;
1404 indent_up();
1405
1406 out << indent() << "$args = thrift_protocol_read_binary_after_message_begin(" <<endl;
1407
1408 indent_up();
1409 out << indent() << "$input,"<<endl
1410 << indent() << "'" << argsname << "'," << endl
1411 << indent() << "$input->isStrictRead()" <<endl;
1412
1413 indent_down();
1414 out << indent() <<");" << endl;
1415
1416 indent_down();
1417 out << indent() << "} else {" << endl;
1418
1419 indent_up();
1420 out << indent() << "$args = new " << argsname << "();" << endl
1421 << indent() << "$args->read($input);" << endl;
1422
1423 indent_down();
1424 out << indent() << "}" << endl;
1425
1426 if (!binary_inline_) {
1427 out << indent() << "$input->readMessageEnd();" << endl;
1428 }
1429
1430 t_struct* xs = tfunction->get_xceptions();
1431 const std::vector<t_field*>& xceptions = xs->get_members();
1432 vector<t_field*>::const_iterator x_iter;
1433
1434 // Declare result for non oneway function
1435 if (!tfunction->is_oneway()) {
1436 out << indent() << "$result = new " << resultname << "();" << endl;
1437 }
1438
1439 // Try block for a function with exceptions
1440 if (xceptions.size() > 0) {
1441 out << indent() << "try {" << endl;
1442 indent_up();
1443 }
1444
1445 // Generate the function call
1446 t_struct* arg_struct = tfunction->get_arglist();
1447 const std::vector<t_field*>& fields = arg_struct->get_members();
1448 vector<t_field*>::const_iterator f_iter;
1449
1450 out << indent();
1451 if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
1452 out << "$result->success = ";
1453 }
1454 out << "$this->handler_->" << tfunction->get_name() << "(";
1455 bool first = true;
1456 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1457 if (first) {
1458 first = false;
1459 } else {
1460 out << ", ";
1461 }
1462 out << "$args->" << (*f_iter)->get_name();
1463 }
1464 out << ");" << endl;
1465
1466 if (!tfunction->is_oneway() && xceptions.size() > 0) {
1467 indent_down();
1468 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1469 out << indent() << "} catch ("
1470 << php_namespace(get_true_type((*x_iter)->get_type())->get_program())
1471 << (*x_iter)->get_type()->get_name() << " $" << (*x_iter)->get_name() << ") {"
1472 << endl;
1473 if (!tfunction->is_oneway()) {
1474 indent_up();
1475 out << indent() << "$result->" << (*x_iter)->get_name() << " = $"
1476 << (*x_iter)->get_name() << ";" << endl;
1477 indent_down();
1478 out << indent();
1479 }
1480 }
1481 out << "}" << endl;
1482 }
1483
1484 // Shortcut out here for oneway functions
1485 if (tfunction->is_oneway()) {
1486 out << indent() << "return;" << endl;
1487 indent_down();
1488 out << indent() << "}" << endl;
1489 return;
1490 }
1491
1492 out << indent() << "$bin_accel = ($output instanceof "
1493 << "TBinaryProtocolAccelerated) && function_exists('thrift_protocol_write_binary');"
1494 << endl;
1495
1496 out << indent() << "if ($bin_accel) {" << endl;
1497 indent_up();
1498
1499 out << indent() << "thrift_protocol_write_binary(" << endl;
1500
1501 indent_up();
1502 out << indent() << "$output,"<<endl
1503 << indent() << "'" << tfunction->get_name()<< "'," <<endl
1504 << indent() << "TMessageType::REPLY,"<< endl
1505 << indent() << "$result," << endl
1506 << indent() << "$seqid," << endl
1507 << indent() << "$output->isStrictWrite()"<<endl;
1508
1509 indent_down();
1510 out << indent() << ");" << endl;
1511
1512 indent_down();
1513 out << indent() << "} else {" << endl;
1514 indent_up();
1515
1516 // Serialize the request header
1517 if (binary_inline_) {
1518 out << indent() << "$buff = pack('N', (0x80010000 | "
1519 << "TMessageType::REPLY)); " << endl << indent() << "$buff .= pack('N', strlen('"
1520 << tfunction->get_name() << "'));" << endl << indent() << "$buff .= '"
1521 << tfunction->get_name() << "';" << endl << indent() << "$buff .= pack('N', $seqid);"
1522 << endl << indent() << "$result->write($buff);" << endl << indent()
1523 << "$output->write($buff);" << endl << indent() << "$output->flush();" << endl;
1524 } else {
1525 out << indent() << "$output->writeMessageBegin('" << tfunction->get_name() << "', "
1526 << "TMessageType::REPLY, $seqid);" << endl << indent() << "$result->write($output);"
1527 << endl << indent() << "$output->writeMessageEnd();" << endl << indent()
1528 << "$output->getTransport()->flush();" << endl;
1529 }
1530
1531 scope_down(out);
1532
1533 // Close function
1534 indent_down();
1535 out << indent() << "}" << endl;
1536 }
1537
1538 /**
1539 * Generates helper functions for a service.
1540 *
1541 * @param tservice The service to generate a header definition for
1542 */
1543 void t_php_generator::generate_service_helpers(t_service* tservice) {
1544 vector<t_function*> functions = tservice->get_functions();
1545 vector<t_function*>::iterator f_iter;
1546
1547 ofstream_with_content_based_conditional_update& f_struct_definition = f_service_;
1548 if (classmap_) {
1549 f_struct_definition << "// HELPER FUNCTIONS AND STRUCTURES" << endl << endl;
1550 }
1551
1552 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1553 t_struct* ts = (*f_iter)->get_arglist();
1554 string name = ts->get_name();
1555 ts->set_name(service_name_ + "_" + name);
1556
1557 if (!classmap_) {
1558 string f_struct_definition_name = package_dir_ + service_name_ + "_" + name + ".php";
1559 f_struct_definition.open(f_struct_definition_name.c_str());
1560 generate_service_header(tservice, f_struct_definition);
1561 }
1562
1563 generate_php_struct_definition(f_struct_definition, ts);
1564 if (!classmap_) {
1565 f_struct_definition.close();
1566 }
1567
1568 generate_php_function_helpers(tservice, *f_iter);
1569 ts->set_name(name);
1570 }
1571 }
1572
1573 /**
1574 * Generates a struct and helpers for a function.
1575 *
1576 * @param tfunction The function
1577 */
1578 void t_php_generator::generate_php_function_helpers(t_service* tservice, t_function* tfunction) {
1579 if (!tfunction->is_oneway()) {
1580 t_struct result(program_, service_name_ + "_" + tfunction->get_name() + "_result");
1581 t_field success(tfunction->get_returntype(), "success", 0);
1582 if (!tfunction->get_returntype()->is_void()) {
1583 result.append(&success);
1584 }
1585
1586 t_struct* xs = tfunction->get_xceptions();
1587 const vector<t_field*>& fields = xs->get_members();
1588 vector<t_field*>::const_iterator f_iter;
1589 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1590 result.append(*f_iter);
1591 }
1592
1593 ofstream_with_content_based_conditional_update& f_struct_helper = f_service_;
1594 if (!classmap_) {
1595 string f_struct_helper_name = package_dir_ + result.get_name() + ".php";
1596 f_struct_helper.open(f_struct_helper_name.c_str());
1597 generate_service_header(tservice, f_struct_helper);
1598 }
1599 generate_php_struct_definition(f_struct_helper, &result, false, true);
1600 if (!classmap_) {
1601 f_struct_helper.close();
1602 }
1603 }
1604 }
1605
1606 /**
1607 * Generates a service interface definition.
1608 *
1609 * @param tservice The service to generate a header definition for
1610 */
1611 void t_php_generator::generate_service_interface(t_service* tservice) {
1612 ofstream_with_content_based_conditional_update& f_service_interface = f_service_;
1613 if (!classmap_) {
1614 string f_service_interface_name = package_dir_ + service_name_ + "If.php";
1615 f_service_interface.open(f_service_interface_name.c_str());
1616 generate_service_header(tservice, f_service_interface);
1617 }
1618
1619 string extends = "";
1620 string extends_if = "";
1621 if (tservice->get_extends() != NULL) {
1622 extends = " extends " + php_namespace(tservice->get_extends()->get_program())
1623 + tservice->get_extends()->get_name();
1624 extends_if = " extends " + php_namespace(tservice->get_extends()->get_program())
1625 + tservice->get_extends()->get_name() + "If";
1626 }
1627 generate_php_doc(f_service_interface, tservice);
1628 f_service_interface << "interface " << php_namespace_declaration(tservice) << "If" << extends_if << endl
1629 << "{" << endl;
1630
1631 indent_up();
1632 vector<t_function*> functions = tservice->get_functions();
1633 vector<t_function*>::iterator f_iter;
1634 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1635 generate_php_doc(f_service_interface, *f_iter);
1636 indent(f_service_interface) << "public function " << function_signature(*f_iter) << ";" << endl;
1637 }
1638 indent_down();
1639 f_service_interface << "}" << endl;
1640
1641 // Close service interface file
1642 if (!classmap_) {
1643 f_service_interface.close();
1644 }
1645 }
1646
1647 /**
1648 * Generates a REST interface
1649 */
1650 void t_php_generator::generate_service_rest(t_service* tservice) {
1651 ofstream_with_content_based_conditional_update& f_service_rest = f_service_;
1652 if (!classmap_) {
1653 string f_service_rest_name = package_dir_ + service_name_ + "Rest.php";
1654 f_service_rest.open(f_service_rest_name.c_str());
1655 generate_service_header(tservice, f_service_rest);
1656 }
1657
1658 string extends = "";
1659 string extends_if = "";
1660 if (tservice->get_extends() != NULL) {
1661 extends = " extends " + php_namespace(tservice->get_extends()->get_program())
1662 + tservice->get_extends()->get_name();
1663 extends_if = " extends " + php_namespace(tservice->get_extends()->get_program())
1664 + tservice->get_extends()->get_name() + "Rest";
1665 }
1666 f_service_rest << "class " << service_name_ << "Rest" << extends_if << endl
1667 << "{" << endl;
1668 indent_up();
1669
1670 if (extends.empty()) {
1671 f_service_rest << indent() << "protected $impl_;" << endl << endl;
1672 }
1673
1674 f_service_rest << indent() << "public function __construct($impl) {" << endl << indent()
1675 << " $this->impl_ = $impl;" << endl << indent() << "}" << endl << endl;
1676
1677 vector<t_function*> functions = tservice->get_functions();
1678 vector<t_function*>::iterator f_iter;
1679 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1680 indent(f_service_rest) << "public function " << (*f_iter)->get_name() << "($request) {" << endl;
1681 indent_up();
1682 const vector<t_field*>& args = (*f_iter)->get_arglist()->get_members();
1683 vector<t_field*>::const_iterator a_iter;
1684 for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
1685 t_type* atype = get_true_type((*a_iter)->get_type());
1686 string cast = type_to_cast(atype);
1687 string req = "$request['" + (*a_iter)->get_name() + "']";
1688 if (atype->is_bool()) {
1689 f_service_rest << indent() << "$" << (*a_iter)->get_name() << " = " << cast << "(!empty(" << req
1690 << ") && (" << req << " !== 'false'));" << endl;
1691 } else {
1692 f_service_rest << indent() << "$" << (*a_iter)->get_name() << " = isset(" << req << ") ? "
1693 << cast << req << " : null;" << endl;
1694 }
1695 if (atype->is_string() && ((t_base_type*)atype)->is_string_list()) {
1696 f_service_rest << indent() << "$" << (*a_iter)->get_name() << " = explode(',', $"
1697 << (*a_iter)->get_name() << ");" << endl;
1698 } else if (atype->is_map() || atype->is_list()) {
1699 f_service_rest << indent() << "$" << (*a_iter)->get_name() << " = json_decode($"
1700 << (*a_iter)->get_name() << ", true);" << endl;
1701 } else if (atype->is_set()) {
1702 f_service_rest << indent() << "$" << (*a_iter)->get_name() << " = array_fill_keys(json_decode($"
1703 << (*a_iter)->get_name() << ", true), 1);" << endl;
1704 } else if (atype->is_struct() || atype->is_xception()) {
1705 f_service_rest << indent() << "if ($" << (*a_iter)->get_name() << " !== null) {" << endl
1706 << indent() << " $" << (*a_iter)->get_name() << " = new "
1707 << php_namespace(atype->get_program()) << atype->get_name() << "(json_decode($"
1708 << (*a_iter)->get_name() << ", true));" << endl << indent() << "}" << endl;
1709 }
1710 }
1711 f_service_rest << indent() << "return $this->impl_->" << (*f_iter)->get_name() << "("
1712 << argument_list((*f_iter)->get_arglist(), false) << ");" << endl;
1713 indent_down();
1714 indent(f_service_rest) << "}" << endl << endl;
1715 }
1716 indent_down();
1717 f_service_rest << "}" << endl << endl;
1718
1719 // Close service rest file
1720 f_service_rest << endl;
1721 if (!classmap_) {
1722 f_service_rest.close();
1723 }
1724 }
1725
1726 /**
1727 * Generates a service client definition.
1728 *
1729 * @param tservice The service to generate a server for.
1730 */
1731 void t_php_generator::generate_service_client(t_service* tservice) {
1732 ofstream_with_content_based_conditional_update& f_service_client = f_service_;
1733 if (!classmap_) {
1734 string f_service_client_name = package_dir_ + service_name_ + "Client.php";
1735 f_service_client.open(f_service_client_name.c_str());
1736 generate_service_header(tservice, f_service_client);
1737 }
1738
1739 string extends = "";
1740 string extends_client = "";
1741 if (tservice->get_extends() != NULL) {
1742 extends = tservice->get_extends()->get_name();
1743 extends_client = " extends " + php_namespace(tservice->get_extends()->get_program()) + extends
1744 + "Client";
1745 }
1746
1747 f_service_client << "class " << php_namespace_declaration(tservice) << "Client" << extends_client
1748 << " implements " << php_namespace(tservice->get_program()) << service_name_ << "If" << endl
1749 <<"{"<< endl;
1750 indent_up();
1751
1752 // Private members
1753 if (extends.empty()) {
1754 f_service_client << indent() << "protected $input_ = null;" << endl << indent()
1755 << "protected $output_ = null;" << endl << endl;
1756 f_service_client << indent() << "protected $seqid_ = 0;" << endl << endl;
1757 }
1758
1759 // Constructor function
1760 f_service_client << indent() << "public function __construct($input, $output = null)" << endl
1761 << indent() << "{" << endl;
1762
1763 indent_up();
1764 if (!extends.empty()) {
1765 f_service_client << indent() << "parent::__construct($input, $output);" << endl;
1766 } else {
1767 f_service_client << indent() << "$this->input_ = $input;" << endl
1768 << indent() << "$this->output_ = $output ? $output : $input;" << endl;
1769 }
1770
1771 indent_down();
1772 f_service_client << indent() << "}" << endl << endl;
1773
1774 // Generate client method implementations
1775 vector<t_function*> functions = tservice->get_functions();
1776 vector<t_function*>::const_iterator f_iter;
1777 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1778 t_struct* arg_struct = (*f_iter)->get_arglist();
1779 const vector<t_field*>& fields = arg_struct->get_members();
1780 vector<t_field*>::const_iterator fld_iter;
1781 string funname = (*f_iter)->get_name();
1782
1783 f_service_client << endl;
1784
1785 // Open function
1786 indent(f_service_client) << "public function " << function_signature(*f_iter) << endl;
1787 scope_up(f_service_client);
1788 indent(f_service_client) << "$this->send_" << funname << "(";
1789
1790 bool first = true;
1791 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1792 if (first) {
1793 first = false;
1794 } else {
1795 f_service_client << ", ";
1796 }
1797 f_service_client << "$" << (*fld_iter)->get_name();
1798 }
1799 f_service_client << ");" << endl;
1800
1801 if (!(*f_iter)->is_oneway()) {
1802 f_service_client << indent();
1803 if (!(*f_iter)->get_returntype()->is_void()) {
1804 f_service_client << "return ";
1805 }
1806 f_service_client << "$this->recv_" << funname << "();" << endl;
1807 }
1808 scope_down(f_service_client);
1809 f_service_client << endl;
1810
1811 indent(f_service_client) << "public function send_" << function_signature(*f_iter) << endl;
1812 scope_up(f_service_client);
1813
1814 std::string argsname = php_namespace(tservice->get_program()) + service_name_ + "_"
1815 + (*f_iter)->get_name() + "_args";
1816
1817 f_service_client << indent() << "$args = new " << argsname << "();" << endl;
1818
1819 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1820 f_service_client << indent() << "$args->" << (*fld_iter)->get_name() << " = $"
1821 << (*fld_iter)->get_name() << ";" << endl;
1822 }
1823
1824 f_service_client << indent() << "$bin_accel = ($this->output_ instanceof "
1825 << "TBinaryProtocolAccelerated) && function_exists('thrift_protocol_write_binary');"
1826 << endl;
1827
1828 f_service_client << indent() << "if ($bin_accel) {" << endl;
1829 indent_up();
1830
1831 string messageType = (*f_iter)->is_oneway() ? "TMessageType::ONEWAY" : "TMessageType::CALL";
1832
1833 f_service_client << indent() << "thrift_protocol_write_binary(" << endl;
1834
1835 indent_up();
1836 f_service_client << indent() << "$this->output_," << endl
1837 << indent() << "'" << (*f_iter)->get_name() << "'," << endl
1838 << indent() << messageType << "," << endl
1839 << indent() << "$args," << endl
1840 << indent() << "$this->seqid_," << endl
1841 << indent() << "$this->output_->isStrictWrite()" << endl;
1842
1843 indent_down();
1844 f_service_client << indent() << ");" << endl;
1845
1846 indent_down();
1847 f_service_client << indent() << "} else {" << endl;
1848 indent_up();
1849
1850 // Serialize the request header
1851 if (binary_inline_) {
1852 f_service_client << indent() << "$buff = pack('N', (0x80010000 | " << messageType << "));" << endl
1853 << indent() << "$buff .= pack('N', strlen('" << funname << "'));" << endl
1854 << indent() << "$buff .= '" << funname << "';" << endl << indent()
1855 << "$buff .= pack('N', $this->seqid_);" << endl;
1856 } else {
1857 f_service_client << indent() << "$this->output_->writeMessageBegin('" << (*f_iter)->get_name()
1858 << "', " << messageType << ", $this->seqid_);" << endl;
1859 }
1860
1861 // Write to the stream
1862 if (binary_inline_) {
1863 f_service_client << indent() << "$args->write($buff);" << endl << indent()
1864 << "$this->output_->write($buff);" << endl << indent()
1865 << "$this->output_->flush();" << endl;
1866 } else {
1867 f_service_client << indent() << "$args->write($this->output_);" << endl << indent()
1868 << "$this->output_->writeMessageEnd();" << endl << indent()
1869 << "$this->output_->getTransport()->flush();" << endl;
1870 }
1871
1872 scope_down(f_service_client);
1873
1874 scope_down(f_service_client);
1875
1876 if (!(*f_iter)->is_oneway()) {
1877 std::string resultname = php_namespace(tservice->get_program()) + service_name_ + "_"
1878 + (*f_iter)->get_name() + "_result";
1879 t_struct noargs(program_);
1880
1881 t_function recv_function((*f_iter)->get_returntype(),
1882 string("recv_") + (*f_iter)->get_name(),
1883 &noargs);
1884 // Open function
1885 f_service_client << endl << indent() << "public function " << function_signature(&recv_function)
1886 << endl;
1887 scope_up(f_service_client);
1888
1889 f_service_client << indent() << "$bin_accel = ($this->input_ instanceof "
1890 << "TBinaryProtocolAccelerated)"
1891 << " && function_exists('thrift_protocol_read_binary');" << endl;
1892
1893 f_service_client << indent() << "if ($bin_accel) {" << endl;
1894
1895 indent_up();
1896 f_service_client << indent() << "$result = thrift_protocol_read_binary(" << endl;
1897
1898 indent_up();
1899 f_service_client << indent() << "$this->input_," << endl
1900 << indent() << "'" << resultname << "'," << endl
1901 << indent() << "$this->input_->isStrictRead()" << endl;
1902
1903 indent_down();
1904 f_service_client << indent() << ");" << endl;
1905
1906 indent_down();
1907 f_service_client << indent() << "} else {" << endl;
1908
1909 indent_up();
1910 f_service_client << indent() << "$rseqid = 0;" << endl
1911 << indent() << "$fname = null;" << endl
1912 << indent() << "$mtype = 0;" << endl << endl;
1913
1914 if (binary_inline_) {
1915 t_field ffname(g_type_string, "fname");
1916 t_field fseqid(g_type_i32, "rseqid");
1917 f_service_client << indent() << "$ver = unpack('N', $this->input_->readAll(4));" << endl
1918 << indent() << "$ver = $ver[1];" << endl << indent() << "$mtype = $ver & 0xff;"
1919 << endl << indent() << "$ver = $ver & 0xffff0000;" << endl << indent()
1920 << "if ($ver != 0x80010000) throw new "
1921 << "TProtocolException('Bad version identifier: '.$ver, "
1922 << "TProtocolException::BAD_VERSION);" << endl;
1923 generate_deserialize_field(f_service_client, &ffname, "", true);
1924 generate_deserialize_field(f_service_client, &fseqid, "", true);
1925 } else {
1926 f_service_client << indent() << "$this->input_->readMessageBegin($fname, $mtype, $rseqid);" << endl
1927 << indent() << "if ($mtype == TMessageType::EXCEPTION) {" << endl;
1928
1929 indent_up();
1930 f_service_client << indent() << "$x = new TApplicationException();" << endl
1931 << indent() << "$x->read($this->input_);" << endl
1932 << indent() << "$this->input_->readMessageEnd();" << endl
1933 << indent() << "throw $x;" << endl;
1934 indent_down();
1935 f_service_client << indent() << "}" << endl;
1936 }
1937
1938 f_service_client << indent() << "$result = new " << resultname << "();" << endl
1939 << indent() << "$result->read($this->input_);" << endl;
1940
1941 if (!binary_inline_) {
1942 f_service_client << indent() << "$this->input_->readMessageEnd();" << endl;
1943 }
1944
1945 scope_down(f_service_client);
1946
1947 // Careful, only return result if not a void function
1948 if (!(*f_iter)->get_returntype()->is_void()) {
1949 f_service_client << indent() << "if ($result->success !== null) {" << endl;
1950
1951 indent_up();
1952 f_service_client << indent() << "return $result->success;" << endl;
1953
1954 indent_down();
1955 f_service_client << indent() << "}" << endl;
1956 }
1957
1958 t_struct* xs = (*f_iter)->get_xceptions();
1959 const std::vector<t_field*>& xceptions = xs->get_members();
1960 vector<t_field*>::const_iterator x_iter;
1961 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1962 f_service_client << indent() << "if ($result->" << (*x_iter)->get_name() << " !== null) {" << endl;
1963
1964 indent_up();
1965 f_service_client << indent() << "throw $result->" << (*x_iter)->get_name() << ";" << endl;
1966
1967 indent_down();
1968 f_service_client << indent() << "}" << endl;
1969 }
1970
1971 // Careful, only return _result if not a void function
1972 if ((*f_iter)->get_returntype()->is_void()) {
1973 indent(f_service_client) << "return;" << endl;
1974 } else {
1975 f_service_client << indent() << "throw new \\Exception(\"" << (*f_iter)->get_name()
1976 << " failed: unknown result\");" << endl;
1977 }
1978
1979 // Close function
1980 scope_down(f_service_client);
1981 }
1982 }
1983
1984 indent_down();
1985 f_service_client << "}" << endl;
1986
1987 // Close service client file
1988 if (!classmap_) {
1989 f_service_client.close();
1990 }
1991 }
1992
1993 /**
1994 * Deserializes a field of any type.
1995 */
1996 void t_php_generator::generate_deserialize_field(ostream& out,
1997 t_field* tfield,
1998 string prefix,
1999 bool inclass) {
2000 t_type* type = get_true_type(tfield->get_type());
2001
2002 if (type->is_void()) {
2003 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
2004 }
2005
2006 string name = prefix + tfield->get_name();
2007
2008 if (type->is_struct() || type->is_xception()) {
2009 generate_deserialize_struct(out, (t_struct*)type, name);
2010 } else {
2011
2012 if (type->is_container()) {
2013 generate_deserialize_container(out, type, name);
2014 } else if (type->is_base_type() || type->is_enum()) {
2015
2016 if (binary_inline_) {
2017 std::string itrans = (inclass ? "$this->input_" : "$input");
2018
2019 if (type->is_base_type()) {
2020 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2021 switch (tbase) {
2022 case t_base_type::TYPE_VOID:
2023 throw "compiler error: cannot serialize void field in a struct: " + name;
2024 break;
2025 case t_base_type::TYPE_STRING:
2026 out << indent() << "$len = unpack('N', " << itrans << "->readAll(4));" << endl
2027 << indent() << "$len = $len[1];" << endl << indent() << "if ($len > 0x7fffffff) {"
2028 << endl << indent() << " $len = 0 - (($len - 1) ^ 0xffffffff);" << endl << indent()
2029 << "}" << endl << indent() << "$" << name << " = " << itrans << "->readAll($len);"
2030 << endl;
2031 break;
2032 case t_base_type::TYPE_BOOL:
2033 out << indent() << "$" << name << " = unpack('c', " << itrans << "->readAll(1));"
2034 << endl << indent() << "$" << name << " = (bool)$" << name << "[1];" << endl;
2035 break;
2036 case t_base_type::TYPE_I8:
2037 out << indent() << "$" << name << " = unpack('c', " << itrans << "->readAll(1));"
2038 << endl << indent() << "$" << name << " = $" << name << "[1];" << endl;
2039 break;
2040 case t_base_type::TYPE_I16:
2041 out << indent() << "$val = unpack('n', " << itrans << "->readAll(2));" << endl
2042 << indent() << "$val = $val[1];" << endl << indent() << "if ($val > 0x7fff) {"
2043 << endl << indent() << " $val = 0 - (($val - 1) ^ 0xffff);" << endl << indent()
2044 << "}" << endl << indent() << "$" << name << " = $val;" << endl;
2045 break;
2046 case t_base_type::TYPE_I32:
2047 out << indent() << "$val = unpack('N', " << itrans << "->readAll(4));" << endl
2048 << indent() << "$val = $val[1];" << endl << indent() << "if ($val > 0x7fffffff) {"
2049 << endl << indent() << " $val = 0 - (($val - 1) ^ 0xffffffff);" << endl << indent()
2050 << "}" << endl << indent() << "$" << name << " = $val;" << endl;
2051 break;
2052 case t_base_type::TYPE_I64:
2053 out << indent() << "$arr = unpack('N2', " << itrans << "->readAll(8));" << endl
2054 << indent() << "if ($arr[1] & 0x80000000) {" << endl << indent()
2055 << " $arr[1] = $arr[1] ^ 0xFFFFFFFF;" << endl << indent()
2056 << " $arr[2] = $arr[2] ^ 0xFFFFFFFF;" << endl << indent() << " $" << name
2057 << " = 0 - $arr[1]*4294967296 - $arr[2] - 1;" << endl << indent() << "} else {"
2058 << endl << indent() << " $" << name << " = $arr[1]*4294967296 + $arr[2];" << endl
2059 << indent() << "}" << endl;
2060 break;
2061 case t_base_type::TYPE_DOUBLE:
2062 out << indent() << "$arr = unpack('d', strrev(" << itrans << "->readAll(8)));" << endl
2063 << indent() << "$" << name << " = $arr[1];" << endl;
2064 break;
2065 default:
2066 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase)
2067 + tfield->get_name();
2068 }
2069 } else if (type->is_enum()) {
2070 out << indent() << "$val = unpack('N', " << itrans << "->readAll(4));" << endl << indent()
2071 << "$val = $val[1];" << endl << indent() << "if ($val > 0x7fffffff) {" << endl
2072 << indent() << " $val = 0 - (($val - 1) ^ 0xffffffff);" << endl << indent() << "}"
2073 << endl << indent() << "$" << name << " = $val;" << endl;
2074 }
2075 } else {
2076
2077 indent(out) << "$xfer += $input->";
2078
2079 if (type->is_base_type()) {
2080 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2081 switch (tbase) {
2082 case t_base_type::TYPE_VOID:
2083 throw "compiler error: cannot serialize void field in a struct: " + name;
2084 break;
2085 case t_base_type::TYPE_STRING:
2086 out << "readString($" << name << ");";
2087 break;
2088 case t_base_type::TYPE_BOOL:
2089 out << "readBool($" << name << ");";
2090 break;
2091 case t_base_type::TYPE_I8:
2092 out << "readByte($" << name << ");";
2093 break;
2094 case t_base_type::TYPE_I16:
2095 out << "readI16($" << name << ");";
2096 break;
2097 case t_base_type::TYPE_I32:
2098 out << "readI32($" << name << ");";
2099 break;
2100 case t_base_type::TYPE_I64:
2101 out << "readI64($" << name << ");";
2102 break;
2103 case t_base_type::TYPE_DOUBLE:
2104 out << "readDouble($" << name << ");";
2105 break;
2106 default:
2107 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase);
2108 }
2109 } else if (type->is_enum()) {
2110 out << "readI32($" << name << ");";
2111 }
2112 out << endl;
2113 }
2114 } else {
2115 printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
2116 tfield->get_name().c_str(),
2117 type->get_name().c_str());
2118 }
2119 }
2120 }
2121
2122 /**
2123 * Generates an unserializer for a variable. This makes two key assumptions,
2124 * first that there is a const char* variable named data that points to the
2125 * buffer for deserialization, and that there is a variable protocol which
2126 * is a reference to a TProtocol serialization object.
2127 */
2128 void t_php_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix) {
2129 out << indent() << "$" << prefix << " = new " << php_namespace(tstruct->get_program())
2130 << tstruct->get_name() << "();" << endl << indent() << "$xfer += $" << prefix
2131 << "->read($input);" << endl;
2132 }
2133
2134 void t_php_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix) {
2135 string size = tmp("_size");
2136 string ktype = tmp("_ktype");
2137 string vtype = tmp("_vtype");
2138 string etype = tmp("_etype");
2139
2140 t_field fsize(g_type_i32, size);
2141 t_field fktype(g_type_i8, ktype);
2142 t_field fvtype(g_type_i8, vtype);
2143 t_field fetype(g_type_i8, etype);
2144
2145 out << indent() << "$" << prefix << " = array();" << endl << indent() << "$" << size << " = 0;"
2146 << endl;
2147
2148 // Declare variables, read header
2149 if (ttype->is_map()) {
2150 out << indent() << "$" << ktype << " = 0;" << endl << indent() << "$" << vtype << " = 0;"
2151 << endl;
2152 if (binary_inline_) {
2153 generate_deserialize_field(out, &fktype);
2154 generate_deserialize_field(out, &fvtype);
2155 generate_deserialize_field(out, &fsize);
2156 } else {
2157 out << indent() << "$xfer += $input->readMapBegin("
2158 << "$" << ktype << ", $" << vtype << ", $" << size << ");" << endl;
2159 }
2160 } else if (ttype->is_set()) {
2161 if (binary_inline_) {
2162 generate_deserialize_field(out, &fetype);
2163 generate_deserialize_field(out, &fsize);
2164 } else {
2165 out << indent() << "$" << etype << " = 0;" << endl << indent()
2166 << "$xfer += $input->readSetBegin("
2167 << "$" << etype << ", $" << size << ");" << endl;
2168 }
2169 } else if (ttype->is_list()) {
2170 if (binary_inline_) {
2171 generate_deserialize_field(out, &fetype);
2172 generate_deserialize_field(out, &fsize);
2173 } else {
2174 out << indent() << "$" << etype << " = 0;" << endl << indent()
2175 << "$xfer += $input->readListBegin("
2176 << "$" << etype << ", $" << size << ");" << endl;
2177 }
2178 }
2179
2180 // For loop iterates over elements
2181 string i = tmp("_i");
2182 indent(out) << "for ($" << i << " = 0; $" << i << " < $" << size << "; ++$" << i << ") {" << endl;
2183
2184 indent_up();
2185
2186 if (ttype->is_map()) {
2187 generate_deserialize_map_element(out, (t_map*)ttype, prefix);
2188 } else if (ttype->is_set()) {
2189 generate_deserialize_set_element(out, (t_set*)ttype, prefix);
2190 } else if (ttype->is_list()) {
2191 generate_deserialize_list_element(out, (t_list*)ttype, prefix);
2192 }
2193
2194 scope_down(out);
2195
2196 if (!binary_inline_) {
2197 // Read container end
2198 if (ttype->is_map()) {
2199 indent(out) << "$xfer += $input->readMapEnd();" << endl;
2200 } else if (ttype->is_set()) {
2201 indent(out) << "$xfer += $input->readSetEnd();" << endl;
2202 } else if (ttype->is_list()) {
2203 indent(out) << "$xfer += $input->readListEnd();" << endl;
2204 }
2205 }
2206 }
2207
2208 /**
2209 * Generates code to deserialize a map
2210 */
2211 void t_php_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix) {
2212 string key = tmp("key");
2213 string val = tmp("val");
2214 t_field fkey(tmap->get_key_type(), key);
2215 t_field fval(tmap->get_val_type(), val);
2216
2217 indent(out) << declare_field(&fkey, true, true) << endl;
2218 indent(out) << declare_field(&fval, true, true) << endl;
2219
2220 generate_deserialize_field(out, &fkey);
2221 generate_deserialize_field(out, &fval);
2222
2223 indent(out) << "$" << prefix << "[$" << key << "] = $" << val << ";" << endl;
2224 }
2225
2226 void t_php_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix) {
2227 string elem = tmp("elem");
2228 t_field felem(tset->get_elem_type(), elem);
2229
2230 indent(out) << "$" << elem << " = null;" << endl;
2231
2232 generate_deserialize_field(out, &felem);
2233
2234 t_type* elem_type = tset->get_elem_type();
2235 if(php_is_scalar(elem_type)) {
2236 indent(out) << "$" << prefix << "[$" << elem << "] = true;" << endl;
2237 } else {
2238 indent(out) << "$" << prefix << "[] = $" << elem << ";" << endl;
2239 }
2240 }
2241
2242 void t_php_generator::generate_deserialize_list_element(ostream& out,
2243 t_list* tlist,
2244 string prefix) {
2245 string elem = tmp("elem");
2246 t_field felem(tlist->get_elem_type(), elem);
2247
2248 indent(out) << "$" << elem << " = null;" << endl;
2249
2250 generate_deserialize_field(out, &felem);
2251
2252 indent(out) << "$" << prefix << " []= $" << elem << ";" << endl;
2253 }
2254
2255 /**
2256 * Serializes a field of any type.
2257 *
2258 * @param tfield The field to serialize
2259 * @param prefix Name to prepend to field name
2260 */
2261 void t_php_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix) {
2262 t_type* type = get_true_type(tfield->get_type());
2263
2264 // Do nothing for void types
2265 if (type->is_void()) {
2266 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
2267 }
2268
2269 if (type->is_struct() || type->is_xception()) {
2270 generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name());
2271 } else if (type->is_container()) {
2272 generate_serialize_container(out, type, prefix + tfield->get_name());
2273 } else if (type->is_base_type() || type->is_enum()) {
2274
2275 string name = prefix + tfield->get_name();
2276
2277 if (binary_inline_) {
2278 if (type->is_base_type()) {
2279 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2280 switch (tbase) {
2281 case t_base_type::TYPE_VOID:
2282 throw "compiler error: cannot serialize void field in a struct: " + name;
2283 break;
2284 case t_base_type::TYPE_STRING:
2285 out << indent() << "$output .= pack('N', strlen($" << name << "));" << endl << indent()
2286 << "$output .= $" << name << ";" << endl;
2287 break;
2288 case t_base_type::TYPE_BOOL:
2289 out << indent() << "$output .= pack('c', $" << name << " ? 1 : 0);" << endl;
2290 break;
2291 case t_base_type::TYPE_I8:
2292 out << indent() << "$output .= pack('c', $" << name << ");" << endl;
2293 break;
2294 case t_base_type::TYPE_I16:
2295 out << indent() << "$output .= pack('n', $" << name << ");" << endl;
2296 break;
2297 case t_base_type::TYPE_I32:
2298 out << indent() << "$output .= pack('N', $" << name << ");" << endl;
2299 break;
2300 case t_base_type::TYPE_I64:
2301 out << indent() << "$output .= pack('N2', $" << name << " >> 32, $" << name
2302 << " & 0xFFFFFFFF);" << endl;
2303 break;
2304 case t_base_type::TYPE_DOUBLE:
2305 out << indent() << "$output .= strrev(pack('d', $" << name << "));" << endl;
2306 break;
2307 default:
2308 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase);
2309 }
2310 } else if (type->is_enum()) {
2311 out << indent() << "$output .= pack('N', $" << name << ");" << endl;
2312 }
2313 } else {
2314
2315 indent(out) << "$xfer += $output->";
2316
2317 if (type->is_base_type()) {
2318 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2319 switch (tbase) {
2320 case t_base_type::TYPE_VOID:
2321 throw "compiler error: cannot serialize void field in a struct: " + name;
2322 break;
2323 case t_base_type::TYPE_STRING:
2324 out << "writeString($" << name << ");";
2325 break;
2326 case t_base_type::TYPE_BOOL:
2327 out << "writeBool($" << name << ");";
2328 break;
2329 case t_base_type::TYPE_I8:
2330 out << "writeByte($" << name << ");";
2331 break;
2332 case t_base_type::TYPE_I16:
2333 out << "writeI16($" << name << ");";
2334 break;
2335 case t_base_type::TYPE_I32:
2336 out << "writeI32($" << name << ");";
2337 break;
2338 case t_base_type::TYPE_I64:
2339 out << "writeI64($" << name << ");";
2340 break;
2341 case t_base_type::TYPE_DOUBLE:
2342 out << "writeDouble($" << name << ");";
2343 break;
2344 default:
2345 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase);
2346 }
2347 } else if (type->is_enum()) {
2348 out << "writeI32($" << name << ");";
2349 }
2350 out << endl;
2351 }
2352 } else {
2353 printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
2354 prefix.c_str(),
2355 tfield->get_name().c_str(),
2356 type->get_name().c_str());
2357 }
2358 }
2359
2360 /**
2361 * Serializes all the members of a struct.
2362 *
2363 * @param tstruct The struct to serialize
2364 * @param prefix String prefix to attach to all fields
2365 */
2366 void t_php_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) {
2367 (void)tstruct;
2368 indent(out) << "$xfer += $" << prefix << "->write($output);" << endl;
2369 }
2370
2371 /**
2372 * Writes out a container
2373 */
2374 void t_php_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) {
2375 if (ttype->is_map()) {
2376 if (binary_inline_) {
2377 out << indent() << "$output .= pack('c', " << type_to_enum(((t_map*)ttype)->get_key_type())
2378 << ");" << endl << indent() << "$output .= pack('c', "
2379 << type_to_enum(((t_map*)ttype)->get_val_type()) << ");" << endl << indent()
2380 << "$output .= strrev(pack('l', count($" << prefix << ")));" << endl;
2381 } else {
2382 indent(out) << "$output->writeMapBegin(" << type_to_enum(((t_map*)ttype)->get_key_type())
2383 << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", "
2384 << "count($" << prefix << "));" << endl;
2385 }
2386 } else if (ttype->is_set()) {
2387 if (binary_inline_) {
2388 out << indent() << "$output .= pack('c', " << type_to_enum(((t_set*)ttype)->get_elem_type())
2389 << ");" << endl << indent() << "$output .= strrev(pack('l', count($" << prefix << ")));"
2390 << endl;
2391
2392 } else {
2393 indent(out) << "$output->writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type())
2394 << ", "
2395 << "count($" << prefix << "));" << endl;
2396 }
2397 } else if (ttype->is_list()) {
2398 if (binary_inline_) {
2399 out << indent() << "$output .= pack('c', " << type_to_enum(((t_list*)ttype)->get_elem_type())
2400 << ");" << endl << indent() << "$output .= strrev(pack('l', count($" << prefix << ")));"
2401 << endl;
2402
2403 } else {
2404 indent(out) << "$output->writeListBegin(" << type_to_enum(((t_list*)ttype)->get_elem_type())
2405 << ", "
2406 << "count($" << prefix << "));" << endl;
2407 }
2408 }
2409
2410 if (ttype->is_map()) {
2411 string kiter = tmp("kiter");
2412 string viter = tmp("viter");
2413 indent(out) << "foreach ($" << prefix << " as "
2414 << "$" << kiter << " => $" << viter << ") {" << endl;
2415 indent_up();
2416 generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
2417 scope_down(out);
2418 } else if (ttype->is_set()) {
2419 string iter = tmp("iter");
2420 string iter_val = tmp("iter");
2421 indent(out) << "foreach ($" << prefix << " as $" << iter << " => $" << iter_val << ") {" << endl;
2422 indent_up();
2423
2424 t_type* elem_type = ((t_set*)ttype)->get_elem_type();
2425 if(php_is_scalar(elem_type)) {
2426 generate_serialize_set_element(out, (t_set*)ttype, iter);
2427 } else {
2428 generate_serialize_set_element(out, (t_set*)ttype, iter_val);
2429 }
2430 scope_down(out);
2431 } else if (ttype->is_list()) {
2432 string iter = tmp("iter");
2433 indent(out) << "foreach ($" << prefix << " as $" << iter << ") {" << endl;
2434 indent_up();
2435 generate_serialize_list_element(out, (t_list*)ttype, iter);
2436 scope_down(out);
2437 }
2438
2439 if (!binary_inline_) {
2440 if (ttype->is_map()) {
2441 indent(out) << "$output->writeMapEnd();" << endl;
2442 } else if (ttype->is_set()) {
2443 indent(out) << "$output->writeSetEnd();" << endl;
2444 } else if (ttype->is_list()) {
2445 indent(out) << "$output->writeListEnd();" << endl;
2446 }
2447 }
2448 }
2449
2450 /**
2451 * Serializes the members of a map.
2452 *
2453 */
2454 void t_php_generator::generate_serialize_map_element(ostream& out,
2455 t_map* tmap,
2456 string kiter,
2457 string viter) {
2458 t_field kfield(tmap->get_key_type(), kiter);
2459 generate_serialize_field(out, &kfield, "");
2460
2461 t_field vfield(tmap->get_val_type(), viter);
2462 generate_serialize_field(out, &vfield, "");
2463 }
2464
2465 /**
2466 * Serializes the members of a set.
2467 */
2468 void t_php_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) {
2469 t_field efield(tset->get_elem_type(), iter);
2470 generate_serialize_field(out, &efield, "");
2471 }
2472
2473 /**
2474 * Serializes the members of a list.
2475 */
2476 void t_php_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) {
2477 t_field efield(tlist->get_elem_type(), iter);
2478 generate_serialize_field(out, &efield, "");
2479 }
2480
2481 /**
2482 * Emits a PHPDoc comment for the given contents
2483 */
2484 void t_php_generator::generate_php_docstring_comment(ostream& out, string contents) {
2485 generate_docstring_comment(out, "/**\n", " * ", contents, " */\n");
2486 }
2487
2488 /**
2489 * Emits a PHPDoc comment if the provided object has a doc in Thrift
2490 */
2491 void t_php_generator::generate_php_doc(ostream& out, t_doc* tdoc) {
2492 if (tdoc->has_doc()) {
2493 generate_php_docstring_comment(out, tdoc->get_doc());
2494 }
2495 }
2496
2497 /**
2498 * Emits a PHPDoc comment for a field
2499 */
2500 void t_php_generator::generate_php_doc(ostream& out, t_field* field) {
2501 stringstream ss;
2502
2503 // prepend free-style doc if available
2504 if (field->has_doc()) {
2505 ss << field->get_doc() << endl;
2506 }
2507
2508 // append @var tag
2509 t_type* type = get_true_type(field->get_type());
2510 ss << "@var " << type_to_phpdoc(type) << endl;
2511
2512 generate_php_docstring_comment(out, ss.str());
2513 }
2514
2515 /**
2516 * Emits a PHPDoc comment for a function
2517 */
2518 void t_php_generator::generate_php_doc(ostream& out, t_function* function) {
2519 stringstream ss;
2520 if (function->has_doc()) {
2521 ss << function->get_doc() << endl;
2522 }
2523
2524 // generate parameter types doc
2525 const vector<t_field*>& args = function->get_arglist()->get_members();
2526 vector<t_field*>::const_iterator a_iter;
2527 for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
2528 t_field* arg = *a_iter;
2529 ss << "@param " << type_to_phpdoc(arg->get_type()) << " $" << arg->get_name();
2530 if (arg->has_doc()) {
2531 ss << " " << arg->get_doc();
2532 }
2533 ss << endl;
2534 }
2535
2536 // generate return type doc
2537 t_type* ret_type = function->get_returntype();
2538 if (!ret_type->is_void() || ret_type->has_doc()) {
2539 ss << "@return " << type_to_phpdoc(ret_type);
2540 if (ret_type->has_doc()) {
2541 ss << " " << ret_type->get_doc();
2542 }
2543 ss << endl;
2544 }
2545
2546 // generate exceptions doc
2547 const vector<t_field*>& excs = function->get_xceptions()->get_members();
2548 vector<t_field*>::const_iterator e_iter;
2549 for (e_iter = excs.begin(); e_iter != excs.end(); ++e_iter) {
2550 t_field* exc = *e_iter;
2551 ss << "@throws " << type_to_phpdoc(exc->get_type());
2552 if (exc->has_doc()) {
2553 ss << " " << exc->get_doc();
2554 }
2555 ss << endl;
2556 }
2557
2558 generate_docstring_comment(out, "/**\n", " * ", ss.str(), " */\n");
2559 }
2560
2561 /**
2562 * Declares a field, which may include initialization as necessary.
2563 *
2564 * @param ttype The type
2565 */
2566 string t_php_generator::declare_field(t_field* tfield, bool init, bool obj) {
2567 string result = "$" + tfield->get_name();
2568 if (init) {
2569 t_type* type = get_true_type(tfield->get_type());
2570 if (type->is_base_type()) {
2571 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2572 switch (tbase) {
2573 case t_base_type::TYPE_VOID:
2574 break;
2575 case t_base_type::TYPE_STRING:
2576 result += " = ''";
2577 break;
2578 case t_base_type::TYPE_BOOL:
2579 result += " = false";
2580 break;
2581 case t_base_type::TYPE_I8:
2582 case t_base_type::TYPE_I16:
2583 case t_base_type::TYPE_I32:
2584 case t_base_type::TYPE_I64:
2585 result += " = 0";
2586 break;
2587 case t_base_type::TYPE_DOUBLE:
2588 result += " = 0.0";
2589 break;
2590 default:
2591 throw "compiler error: no PHP initializer for base type " + t_base_type::t_base_name(tbase);
2592 }
2593 } else if (type->is_enum()) {
2594 result += " = 0";
2595 } else if (type->is_container()) {
2596 result += " = array()";
2597 } else if (type->is_struct() || type->is_xception()) {
2598 if (obj) {
2599 result += " = new " + php_namespace(type->get_program()) + type->get_name() + "()";
2600 } else {
2601 result += " = null";
2602 }
2603 }
2604 }
2605 return result + ";";
2606 }
2607
2608 /**
2609 * Renders a function signature of the form 'type name(args)'
2610 *
2611 * @param tfunction Function definition
2612 * @return String of rendered function definition
2613 */
2614 string t_php_generator::function_signature(t_function* tfunction, string prefix) {
2615 return prefix + tfunction->get_name() + "(" + argument_list(tfunction->get_arglist()) + ")";
2616 }
2617
2618 /**
2619 * Renders a field list
2620 */
2621 string t_php_generator::argument_list(t_struct* tstruct, bool addTypeHints) {
2622 string result = "";
2623
2624 const vector<t_field*>& fields = tstruct->get_members();
2625 vector<t_field*>::const_iterator f_iter;
2626 bool first = true;
2627 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2628 if (first) {
2629 first = false;
2630 } else {
2631 result += ", ";
2632 }
2633
2634 t_type* type = (*f_iter)->get_type();
2635
2636 // Set type name
2637 if (addTypeHints) {
2638 if (type->is_struct()) {
2639 string className = php_namespace(type->get_program())
2640 + php_namespace_directory("Definition", false)
2641 + classify(type->get_name());
2642
2643 result += className + " ";
2644 } else if (type->is_container()) {
2645 result += "array ";
2646 }
2647 }
2648
2649 result += "$" + (*f_iter)->get_name();
2650 }
2651 return result;
2652 }
2653
2654 /**
2655 * Gets a typecast string for a particular type.
2656 */
2657 string t_php_generator::type_to_cast(t_type* type) {
2658 if (type->is_base_type()) {
2659 t_base_type* btype = (t_base_type*)type;
2660 switch (btype->get_base()) {
2661 case t_base_type::TYPE_BOOL:
2662 return "(bool)";
2663 case t_base_type::TYPE_I8:
2664 case t_base_type::TYPE_I16:
2665 case t_base_type::TYPE_I32:
2666 case t_base_type::TYPE_I64:
2667 return "(int)";
2668 case t_base_type::TYPE_DOUBLE:
2669 return "(double)";
2670 case t_base_type::TYPE_STRING:
2671 return "(string)";
2672 default:
2673 return "";
2674 }
2675 } else if (type->is_enum()) {
2676 return "(int)";
2677 }
2678 return "";
2679 }
2680
2681 /**
2682 * Converts the parse type to a C++ enum string for the given type.
2683 */
2684 string t_php_generator::type_to_enum(t_type* type) {
2685 type = get_true_type(type);
2686
2687 if (type->is_base_type()) {
2688 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2689 switch (tbase) {
2690 case t_base_type::TYPE_VOID:
2691 throw "NO T_VOID CONSTRUCT";
2692 case t_base_type::TYPE_STRING:
2693 return "TType::STRING";
2694 case t_base_type::TYPE_BOOL:
2695 return "TType::BOOL";
2696 case t_base_type::TYPE_I8:
2697 return "TType::BYTE";
2698 case t_base_type::TYPE_I16:
2699 return "TType::I16";
2700 case t_base_type::TYPE_I32:
2701 return "TType::I32";
2702 case t_base_type::TYPE_I64:
2703 return "TType::I64";
2704 case t_base_type::TYPE_DOUBLE:
2705 return "TType::DOUBLE";
2706 }
2707 } else if (type->is_enum()) {
2708 return "TType::I32";
2709 } else if (type->is_struct() || type->is_xception()) {
2710 return "TType::STRUCT";
2711 } else if (type->is_map()) {
2712 return "TType::MAP";
2713 } else if (type->is_set()) {
2714 return "TType::SET";
2715 } else if (type->is_list()) {
2716 return "TType::LST";
2717 }
2718
2719 throw "INVALID TYPE IN type_to_enum: " + type->get_name();
2720 }
2721
2722 /**
2723 * Converts the parse type to a PHPDoc string for the given type.
2724 */
2725 string t_php_generator::type_to_phpdoc(t_type* type) {
2726 type = get_true_type(type);
2727
2728 if (type->is_base_type()) {
2729 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2730 switch (tbase) {
2731 case t_base_type::TYPE_VOID:
2732 return "void";
2733 case t_base_type::TYPE_STRING:
2734 return "string";
2735 case t_base_type::TYPE_BOOL:
2736 return "bool";
2737 case t_base_type::TYPE_I8:
2738 return "int";
2739 case t_base_type::TYPE_I16:
2740 return "int";
2741 case t_base_type::TYPE_I32:
2742 return "int";
2743 case t_base_type::TYPE_I64:
2744 return "int";
2745 case t_base_type::TYPE_DOUBLE:
2746 return "double";
2747 }
2748 } else if (type->is_enum()) {
2749 return "int";
2750 } else if (type->is_struct() || type->is_xception()) {
2751 return php_namespace(type->get_program()) + type->get_name();
2752 } else if (type->is_map()) {
2753 return "array";
2754 } else if (type->is_set()) {
2755 t_set* tset = static_cast<t_set*>(type);
2756 t_type* t_elem = tset->get_elem_type();
2757 if (t_elem->is_container()) {
2758 return "(" + type_to_phpdoc(t_elem) + ")[]";
2759 } else {
2760 return type_to_phpdoc(t_elem) + "[]";
2761 }
2762 } else if (type->is_list()) {
2763 t_list* tlist = static_cast<t_list*>(type);
2764 t_type* t_elem = tlist->get_elem_type();
2765 if (t_elem->is_container()) {
2766 return "(" + type_to_phpdoc(t_elem) + ")[]";
2767 } else {
2768 return type_to_phpdoc(t_elem) + "[]";
2769 }
2770 }
2771
2772 throw "INVALID TYPE IN type_to_enum: " + type->get_name();
2773 }
2774
2775 THRIFT_REGISTER_GENERATOR(
2776 php,
2777 "PHP",
2778 " inlined: Generate PHP inlined files\n"
2779 " server: Generate PHP server stubs\n"
2780 " oop: Generate PHP with object oriented subclasses\n"
2781 " classmap: Generate old-style PHP files (use classmap autoloading)\n"
2782 " rest: Generate PHP REST processors\n"
2783 " nsglobal=NAME: Set global namespace\n"
2784 " validate: Generate PHP validator methods\n"
2785 " json: Generate JsonSerializable classes (requires PHP >= 5.4)\n")