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
10 * http://www.apache.org/licenses/LICENSE-2.0
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
28 #include "thrift/platform.h"
29 #include "thrift/generate/t_oop_generator.h"
33 using std::ostringstream
;
35 using std::stringstream
;
38 static const string endl
= "\n"; // avoid ostream << std::endl flushes
40 #define NSGLOBAL (nsglobal_.size() ? nsglobal_ : "")
41 #define NSGLOBAL_A ("\\" + NSGLOBAL)
42 #define NSGLOBAL_B (NSGLOBAL + "\\")
43 #define NSGLOBAL_AB ("\\" + NSGLOBAL + "\\")
49 class t_php_generator
: public t_oop_generator
{
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
) {
56 std::map
<std::string
, std::string
>::const_iterator iter
;
58 binary_inline_
= false;
63 json_serializable_
= false;
64 nsglobal_
= ""; // by default global namespace is empty
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) {
71 } else if (iter
->first
.compare("server") == 0) {
73 } else if (iter
->first
.compare("oop") == 0) {
75 } else if (iter
->first
.compare("validate") == 0) {
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) {
83 } else if (iter
->first
.compare("psr4") == 0) {
85 throw "psr4 and classmap are mutually exclusive.";
87 pwarning(0, "psr4 is default option! needn't add psr4 option!\n");
90 throw "unknown option php:" + iter
->first
;
94 if (oop_
&& binary_inline_
) {
95 throw "oop and inlined are mutually exclusive.";
98 out_dir_base_
= (binary_inline_
? "gen-phpi" : "gen-php");
102 std::string
indent_str() const override
{
106 static bool is_valid_namespace(const std::string
& sub_namespace
);
109 * Init and close methods
112 void init_generator() override
;
113 void close_generator() override
;
116 * Program-level generation functions
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
;
126 std::string
render_const_value(t_type
* type
, t_const_value
* value
);
132 void generate_php_struct(t_struct
* tstruct
, bool is_exception
);
133 void generate_php_struct_definition(std::ostream
& out
,
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
,
142 std::string method_name
,
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
);
151 void generate_php_type_spec(std::ostream
& out
, t_type
* t
);
152 void generate_php_struct_spec(std::ostream
& out
, t_struct
* tstruct
);
155 * Service-level generation functions
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
);
168 * Serialization constructs
171 void generate_deserialize_field(std::ostream
& out
,
173 std::string prefix
= "",
174 bool inclass
= false);
176 void generate_deserialize_struct(std::ostream
& out
, t_struct
* tstruct
, std::string prefix
= "");
178 void generate_deserialize_container(std::ostream
& out
, t_type
* ttype
, std::string prefix
= "");
180 void generate_deserialize_set_element(std::ostream
& out
, t_set
* tset
, std::string prefix
= "");
182 void generate_deserialize_map_element(std::ostream
& out
, t_map
* tmap
, std::string prefix
= "");
184 void generate_deserialize_list_element(std::ostream
& out
,
186 std::string prefix
= "");
188 void generate_serialize_field(std::ostream
& out
, t_field
* tfield
, std::string prefix
= "");
190 void generate_serialize_struct(std::ostream
& out
, t_struct
* tstruct
, std::string prefix
= "");
192 void generate_serialize_container(std::ostream
& out
, t_type
* ttype
, std::string prefix
= "");
194 void generate_serialize_map_element(std::ostream
& out
,
199 void generate_serialize_set_element(std::ostream
& out
, t_set
* tmap
, std::string iter
);
201 void generate_serialize_list_element(std::ostream
& out
, t_list
* tlist
, std::string iter
);
203 void generate_php_doc(std::ostream
& out
, t_doc
* tdoc
);
205 void generate_php_doc(std::ostream
& out
, t_field
* tfield
);
207 void generate_php_doc(std::ostream
& out
, t_function
* tfunction
);
209 void generate_php_docstring_comment(std::ostream
& out
, string contents
);
212 * Helper rendering functions
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
);
223 bool php_is_scalar(t_type
*ttype
) {
224 ttype
= ttype
->get_true_type();
225 if(ttype
->is_base_type()) {
227 } else if(ttype
->is_enum()) {
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);
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
+ "\\") : "");
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
);
257 + (ns
.size() && NSGLOBAL
.size() ? "\\" : "")
261 // add a directory to already existing namespace
262 string
php_namespace_directory(string directory
, bool end
= true) {
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
+ "\\") : "");
277 // declaring a type: typename or my_namespace_typename
278 string
php_namespace_declaration(t_type
* t
) { return t
->get_name(); }
280 std::string
php_path(t_program
* p
) {
281 std::string ns
= p
->get_namespace("php.path");
283 return p
->get_name();
286 // Transform the java-style namespace into a path.
287 for (char & n
: ns
) {
297 * Transform class_method into ClassMethod
302 string
classify(string str
) {
305 vector
<string
> x
= split(str
, '_');
307 for (const auto & i
: x
) {
308 classe
= classe
+ capitalize(i
);
321 vector
<string
>& split(const string
& s
, char delim
, vector
<string
>& elems
) {
325 while (getline(ss
, item
, delim
)) {
326 elems
.push_back(item
);
332 vector
<string
> split(const string
& s
, char delim
) {
333 vector
<string
> elems
;
335 return split(s
, delim
, elems
);
343 string
capitalize(string str
) {
344 string::iterator
it(str
.begin());
347 str
[0] = toupper((unsigned char)str
[0]);
349 // while(++it != str.end())
351 // *it = tolower((unsigned char)*it);
360 ofstream_with_content_based_conditional_update f_types_
;
361 ofstream_with_content_based_conditional_update f_service_
;
363 std::string package_dir_
;
365 * Generate protocol-independent template? Or Binary inline code?
370 * Generate a REST handler class
375 * Generate stubs for a PHP server
380 * Whether to use OOP base class TBase
385 * Whether to generate old-style PHP file to use classmap autoloading
390 * Whether to generate validator code
395 * Whether to generate JsonSerializable classes
397 bool json_serializable_
;
400 * Global namespace for PHP 5.3
402 std::string nsglobal_
;
405 bool t_php_generator::is_valid_namespace(const std::string
& sub_namespace
) {
406 return sub_namespace
== "path";
410 * Prepares for file generation by opening up the necessary file output
413 * @param tprogram The program to generate
415 void t_php_generator::init_generator() {
416 // Make output directory
417 MKDIR(get_out_dir().c_str());
419 // Create Real directory Namespaces
420 vector
<string
> NSx
= split(php_namespace_suffix(get_program()), '\\');
421 package_dir_
= get_out_dir();
423 for (const auto & i
: NSx
) {
424 package_dir_
= package_dir_
+ "/" + i
+ "/";
425 MKDIR(package_dir_
.c_str());
428 // Prepare output file for all the types in classmap mode
431 string f_types_name
= package_dir_
+ "Types.php";
432 f_types_
.open(f_types_name
.c_str());
433 generate_program_header(f_types_
);
438 * Prints standard php includes
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";
450 if (json_serializable_
) {
451 includes
+= "use JsonSerializable;\n"
459 * Close up (or down) some filez.
461 void t_php_generator::close_generator() {
469 * Generates a typedef. This is not done in PHP, types are all implicit.
471 * @param ttypedef The type definition
473 void t_php_generator::generate_typedef(t_typedef
* ttypedef
) {
478 * Generates service header contains namespace suffix and includes inside file specified
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
486 file
<< autogen_comment() << php_includes();
492 * Generates program header contains namespace suffix and includes inside file specified
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
500 file
<< autogen_comment() << php_includes();
506 * Generates code for an enumerated type. Since define is expensive to lookup
507 * in PHP, we use a global array for this.
509 * @param tenum The enumeration
511 void t_php_generator::generate_enum(t_enum
* tenum
) {
512 ofstream_with_content_based_conditional_update
& f_enum
= f_types_
;
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
);
519 vector
<t_enum_value
*> constants
= tenum
->get_constants();
520 vector
<t_enum_value
*>::iterator c_iter
;
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
525 generate_php_doc(f_enum
, tenum
);
526 f_enum
<< "final class " << tenum
->get_name() << endl
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
537 indent(f_enum
) << "static public $__names = array(" << endl
;
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
;
545 indent(f_enum
) << ");" << endl
;
549 f_enum
<< "}" << endl
<< endl
;
556 * Generate constant class
558 * Override the one from t_generator
560 void t_php_generator::generate_consts(vector
<t_const
*> consts
) {
561 vector
<t_const
*>::iterator c_iter
;
563 // Create class only if needed
564 if (consts
.size() > 0) {
566 ofstream_with_content_based_conditional_update
& f_consts
= f_types_
;
568 string f_consts_name
= package_dir_
+ "Constant.php";
569 f_consts
.open(f_consts_name
.c_str());
570 generate_program_header(f_consts
);
572 f_consts
<< "final class Constant extends \\Thrift\\Type\\TConstant"<< endl
577 // Create static property
578 for (c_iter
= consts
.begin(); c_iter
!= consts
.end(); ++c_iter
) {
579 string name
= (*c_iter
)->get_name();
581 indent(f_consts
) << "static protected $" << name
<< ";" << endl
;
584 // Create init function
585 for (c_iter
= consts
.begin(); c_iter
!= consts
.end(); ++c_iter
) {
586 string name
= (*c_iter
)->get_name();
590 f_consts
<< indent() << "protected static function init_" << name
<< "()" <<endl
591 << indent() << "{" << endl
;
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
;
600 indent(f_consts
) << "}" << endl
;
604 f_consts
<< "}" << endl
;
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
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();
622 case t_base_type::TYPE_STRING
:
623 out
<< '"' << get_escaped_string(value
) << '"';
625 case t_base_type::TYPE_BOOL
:
626 out
<< (value
->get_integer() > 0 ? "true" : "false");
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();
634 case t_base_type::TYPE_DOUBLE
:
635 if (value
->get_type() == t_const_value::CV_INTEGER
) {
636 out
<< value
->get_integer();
638 out
<< value
->get_double();
642 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase
);
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
;
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();
660 if (field_type
== NULL
) {
661 throw "type error: " + type
->get_name() + " has no field " + v_iter
->first
->get_string();
664 out
<< render_const_value(g_type_string
, v_iter
->first
);
666 out
<< render_const_value(field_type
, v_iter
->second
);
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
;
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
) {
680 out
<< render_const_value(ktype
, v_iter
->first
);
682 out
<< render_const_value(vtype
, v_iter
->second
);
687 } else if (type
->is_list() || type
->is_set()) {
689 if (type
->is_list()) {
690 etype
= ((t_list
*)type
)->get_elem_type();
692 etype
= ((t_set
*)type
)->get_elem_type();
694 out
<< "array(" << endl
;
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
) {
700 out
<< render_const_value(etype
, *v_iter
);
701 if (type
->is_set()) {
715 void t_php_generator::generate_struct(t_struct
* tstruct
) {
716 generate_php_struct(tstruct
, false);
720 * Generates a struct definition for a thrift exception. Basically the same
721 * as a struct but extends the Exception class.
723 * @param txception The struct definition
725 void t_php_generator::generate_xception(t_struct
* txception
) {
726 generate_php_struct(txception
, true);
730 * Structs can be normal or exceptions.
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_
;
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
);
739 generate_php_struct_definition(f_struct
, tstruct
, is_exception
);
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
;
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() << "',"
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
;
761 generate_php_type_spec(out
, ktype
);
763 indent(out
) << ")," << endl
;
764 indent(out
) << "'val' => array(" << endl
;
766 generate_php_type_spec(out
, vtype
);
767 indent(out
) << ")," << endl
;
769 } else if (t
->is_list() || t
->is_set()) {
772 etype
= get_true_type(((t_list
*)t
)->get_elem_type());
774 etype
= get_true_type(((t_set
*)t
)->get_elem_type());
776 indent(out
) << "'etype' => " << type_to_enum(etype
) << "," << endl
;
777 indent(out
) << "'elem' => array(" << endl
;
779 generate_php_type_spec(out
, etype
);
780 indent(out
) << ")," << endl
;
783 throw "compiler error: no type for php struct spec field";
788 * Generates the struct specification structure, which fully qualifies enough
789 * type information to generalize serialization routines.
791 void t_php_generator::generate_php_struct_spec(ostream
& out
, t_struct
* tstruct
) {
792 indent(out
) << "static public $_TSPEC = array(" << endl
;
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
;
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
);
805 indent(out
) << ")," << endl
;
809 indent(out
) << ");" << endl
<< endl
;
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...)
817 * @param tstruct The struct definition
819 void t_php_generator::generate_php_struct_definition(ostream
& out
,
823 const vector
<t_field
*>& members
= tstruct
->get_members();
824 vector
<t_field
*>::const_iterator m_iter
;
826 generate_php_doc(out
, tstruct
);
827 out
<< "class " << php_namespace_declaration(tstruct
);
835 if (json_serializable_
) {
836 out
<< " implements JsonSerializable";
842 out
<< indent() << "static public $isValidate = " << (validate_
? "true" : "false") << ";" << endl
<< endl
;
844 generate_php_struct_spec(out
, tstruct
);
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());
852 generate_php_doc(out
, *m_iter
);
853 indent(out
) << "public $" << (*m_iter
)->get_name() << " = " << dval
<< ";" << endl
;
858 // Generate constructor from array
859 string param
= (members
.size() > 0) ? "$vals = null" : "";
860 out
<< indent() << "public function __construct(" << param
<< ")"<< endl
861 << indent() << "{" << endl
;
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
;
872 out
<< indent() << "if (is_array($vals)) {" << endl
;
875 out
<< indent() << "parent::__construct(self::$_TSPEC, $vals);" << endl
;
877 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
) {
878 out
<< indent() << "if (isset($vals['" << (*m_iter
)->get_name() << "'])) {" << endl
;
881 out
<< indent() << "$this->" << (*m_iter
)->get_name() << " = $vals['"
882 << (*m_iter
)->get_name() << "'];" << endl
;
885 out
<< indent() << "}" << endl
;
889 out
<< indent() << "}" << endl
;
894 out
<< indent() << "public function getName()" << endl
895 << indent() << "{" << endl
;
898 out
<< indent() << "return '" << tstruct
->get_name() << "';" << endl
;
901 out
<< indent() << "}" << endl
<< endl
;
904 generate_php_struct_reader(out
, tstruct
, is_result
);
906 generate_php_struct_writer(out
, tstruct
, is_result
);
907 if (needs_php_read_validator(tstruct
, is_result
)) {
909 generate_php_struct_read_validator(out
, tstruct
);
911 if (needs_php_write_validator(tstruct
, is_result
)) {
913 generate_php_struct_write_validator(out
, tstruct
);
915 if (json_serializable_
) {
917 generate_php_struct_json_serialize(out
, tstruct
, is_result
);
921 out
<< indent() << "}" << endl
;
925 * Generates the read() method for a struct
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
;
931 indent(out
) << "public function read($input)" << endl
;
935 if (needs_php_read_validator(tstruct
, is_result
)) {
936 indent(out
) << "$tmp = $this->_read('" << tstruct
->get_name() << "', self::$_TSPEC, $input);"
938 indent(out
) << "$this->_validateForRead();" << endl
;
939 indent(out
) << "return $tmp;" << endl
;
941 indent(out
) << "return $this->_read('" << tstruct
->get_name() << "', self::$_TSPEC, $input);"
949 out
<< indent() << "$xfer = 0;" << endl
<< indent() << "$fname = null;" << endl
<< indent()
950 << "$ftype = 0;" << endl
<< indent() << "$fid = 0;" << endl
;
952 // Declare stack tmp variables
953 if (!binary_inline_
) {
954 indent(out
) << "$xfer += $input->readStructBegin($fname);" << endl
;
957 // Loop over reading in fields
958 indent(out
) << "while (true) {" << endl
;
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
);
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
;
976 indent(out
) << "break;" << endl
;
978 indent(out
) << "}" << endl
;
981 // Switch statement on the field we are reading
982 indent(out
) << "switch ($fid) {" << endl
;
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
;
990 indent(out
) << "if ($ftype == " << type_to_enum((*f_iter
)->get_type()) << ") {" << endl
;
992 generate_deserialize_field(out
, *f_iter
, "this->");
994 out
<< indent() << "} else {" << endl
;
997 if (binary_inline_
) {
998 indent(out
) << "$xfer += TProtocol::skipBinary($input, $ftype);" << endl
;
1000 indent(out
) << "$xfer += $input->skip($ftype);" << endl
;
1004 out
<< indent() << "}" << endl
<< indent() << "break;" << endl
;
1008 // In the default case we skip the field
1009 indent(out
) << "default:" << endl
;
1012 if (binary_inline_
) {
1013 indent(out
) << "$xfer += "
1014 << "TProtocol::skipBinary($input, $ftype);" << endl
;
1016 indent(out
) << "$xfer += $input->skip($ftype);" << endl
;
1018 indent(out
) << "break;" << endl
;
1023 if (!binary_inline_
) {
1024 // Read field end marker
1025 indent(out
) << "$xfer += $input->readFieldEnd();" << endl
;
1030 if (!binary_inline_
) {
1031 indent(out
) << "$xfer += $input->readStructEnd();" << endl
;
1034 if (needs_php_read_validator(tstruct
, is_result
)) {
1035 indent(out
) << "$this->_validateForRead();" << endl
;
1038 indent(out
) << "return $xfer;" << endl
;
1041 out
<< indent() << "}" << endl
;
1045 * Generates the write() method for a struct
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
;
1052 if (binary_inline_
) {
1053 indent(out
) << "public function write(&$output)" << endl
;
1055 indent(out
) << "public function write($output)" << endl
;
1057 indent(out
) << "{" << endl
;
1060 if (needs_php_write_validator(tstruct
, is_result
)) {
1061 indent(out
) << "$this->_validateForWrite();" << endl
;
1065 indent(out
) << "return $this->_write('" << tstruct
->get_name() << "', self::$_TSPEC, $output);"
1072 indent(out
) << "$xfer = 0;" << endl
;
1074 if (!binary_inline_
) {
1075 indent(out
) << "$xfer += $output->writeStructBegin('" << name
<< "');" << endl
;
1078 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
1079 out
<< indent() << "if ($this->" << (*f_iter
)->get_name() << " !== null) {" << endl
;
1082 t_type
* type
= get_true_type((*f_iter
)->get_type());
1084 if (type
->is_container()) {
1086 } else if (type
->is_struct()) {
1089 if (!expect
.empty()) {
1090 out
<< indent() << "if (!is_" << expect
<< "($this->" << (*f_iter
)->get_name() << ")) {"
1093 out
<< indent() << "throw new "
1094 << "TProtocolException('Bad type in structure.', "
1095 << "TProtocolException::INVALID_DATA);" << endl
;
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
;
1104 indent(out
) << "$xfer += $output->writeFieldBegin("
1105 << "'" << (*f_iter
)->get_name() << "', " << type_to_enum((*f_iter
)->get_type())
1106 << ", " << (*f_iter
)->get_key() << ");" << endl
;
1109 // Write field contents
1110 generate_serialize_field(out
, *f_iter
, "this->");
1112 // Write field closer
1113 if (!binary_inline_
) {
1114 indent(out
) << "$xfer += $output->writeFieldEnd();" << endl
;
1118 indent(out
) << "}" << endl
;
1121 if (binary_inline_
) {
1122 out
<< indent() << "$output .= pack('c', "
1123 << "TType::STOP);" << endl
;
1125 out
<< indent() << "$xfer += $output->writeFieldStop();" << endl
<< indent()
1126 << "$xfer += $output->writeStructEnd();" << endl
;
1129 out
<< indent() << "return $xfer;" << endl
;
1132 out
<< indent() << "}" << endl
;
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);
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);
1143 void t_php_generator::generate_php_struct_required_validator(ostream
& out
,
1145 std::string method_name
,
1147 indent(out
) << "private function " << method_name
<< "() {" << endl
;
1150 const vector
<t_field
*>& fields
= tstruct
->get_members();
1152 if (fields
.size() > 0) {
1153 vector
<t_field
*>::const_iterator f_iter
;
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
;
1161 indent(out
) << "throw new TProtocolException('Required field " << tstruct
->get_name() << "."
1162 << field
->get_name() << " is unset!');" << endl
;
1164 indent(out
) << "}" << endl
;
1170 indent(out
) << "}" << endl
;
1173 void t_php_generator::generate_php_struct_json_serialize(ostream
& out
,
1176 indent(out
) << "public function jsonSerialize() {" << endl
;
1179 if (needs_php_write_validator(tstruct
, is_result
)) {
1180 indent(out
) << "$this->_validateForWrite();" << endl
;
1183 indent(out
) << "$json = new stdClass;" << endl
;
1185 const vector
<t_field
*>& fields
= tstruct
->get_members();
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.
1202 indent(out
) << "if ($this->" << name
<< " !== null) {" << endl
;
1204 indent(out
) << "$json->" << name
<< " = ";
1205 if (type
->is_map()) {
1208 out
<< type_to_cast(type
);
1210 out
<< "$this->" << name
<< ";" << endl
;
1212 indent(out
) << "}" << endl
;
1216 indent(out
) << "return $json;" << endl
;
1219 indent(out
) << "}" << endl
;
1222 int t_php_generator::get_php_num_required_fields(const vector
<t_field
*>& fields
, bool write_mode
) {
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
)) {
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);
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));
1248 * Generates a thrift service.
1250 * @param tservice The service definition
1252 void t_php_generator::generate_service(t_service
* tservice
) {
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_
);
1259 // Generate the three main parts of the service (well, two for now in PHP)
1260 generate_service_interface(tservice
);
1262 generate_service_rest(tservice
);
1264 generate_service_client(tservice
);
1265 generate_service_helpers(tservice
);
1267 generate_service_processor(tservice
);
1271 // Close service file
1278 * Generates a service server definition.
1280 * @param tservice The service to generate a server for.
1282 void t_php_generator::generate_service_processor(t_service
* tservice
) {
1283 ofstream_with_content_based_conditional_update
& f_service_processor
= f_service_
;
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
);
1290 // Generate the dispatch methods
1291 vector
<t_function
*> functions
= tservice
->get_functions();
1292 vector
<t_function
*>::iterator f_iter
;
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";
1302 // Generate the header portion
1303 f_service_processor
<< "class " << service_name_
<< "Processor" << extends_processor
<< endl
1307 if (extends
.empty()) {
1308 f_service_processor
<< indent() << "protected $handler_ = null;" << endl
;
1311 f_service_processor
<< indent() << "public function __construct($handler)"<< endl
1312 << indent() << "{" << endl
;
1315 if (extends
.empty()) {
1316 f_service_processor
<< indent() << "$this->handler_ = $handler;" << endl
;
1318 f_service_processor
<< indent() << "parent::__construct($handler);" << endl
;
1322 f_service_processor
<< indent() << "}" << endl
<< endl
;
1324 // Generate the server implementation
1325 f_service_processor
<< indent() << "public function process($input, $output)" << endl
1326 << indent() << "{" << endl
;
1329 f_service_processor
<< indent() << "$rseqid = 0;" << endl
<< indent() << "$fname = null;" << endl
1330 << indent() << "$mtype = 0;" << endl
<< endl
;
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);
1340 f_service_processor
<< indent() << "$input->readMessageBegin($fname, $mtype, $rseqid);" << endl
;
1343 // HOT: check for method implementation
1344 f_service_processor
<< indent() << "$methodname = 'process_'.$fname;" << endl
1345 << indent() << "if (!method_exists($this, $methodname)) {" << endl
;
1348 if (binary_inline_
) {
1349 f_service_processor
<< indent() << "throw new \\Exception('Function '.$fname.' not implemented.');" << endl
;
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
;
1364 f_service_processor
<< indent() << "}" << endl
1365 << indent() << "$this->$methodname($rseqid, $input, $output);" << endl
1366 << indent() << "return true;" << endl
;
1369 f_service_processor
<< indent() << "}" << endl
<< endl
;
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
);
1377 f_service_processor
<< "}" << endl
;
1380 f_service_processor
.close();
1385 * Generates a process function definition.
1387 * @param tfunction The function to write a dispatcher for
1389 void t_php_generator::generate_process_function(std::ostream
& out
, t_service
* tservice
, t_function
* tfunction
) {
1391 out
<< indent() << "protected function process_" << tfunction
->get_name() << "($seqid, $input, $output)" << endl
1392 << indent() << "{" << endl
;
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";
1400 out
<< indent() << "$bin_accel = ($input instanceof "
1401 << "TBinaryProtocolAccelerated) && function_exists('thrift_protocol_read_binary_after_message_begin');"
1403 out
<< indent() << "if ($bin_accel) {" << endl
;
1406 out
<< indent() << "$args = thrift_protocol_read_binary_after_message_begin(" <<endl
;
1409 out
<< indent() << "$input,"<<endl
1410 << indent() << "'" << argsname
<< "'," << endl
1411 << indent() << "$input->isStrictRead()" <<endl
;
1414 out
<< indent() <<");" << endl
;
1417 out
<< indent() << "} else {" << endl
;
1420 out
<< indent() << "$args = new " << argsname
<< "();" << endl
1421 << indent() << "$args->read($input);" << endl
;
1424 out
<< indent() << "}" << endl
;
1426 if (!binary_inline_
) {
1427 out
<< indent() << "$input->readMessageEnd();" << endl
;
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
;
1434 // Declare result for non oneway function
1435 if (!tfunction
->is_oneway()) {
1436 out
<< indent() << "$result = new " << resultname
<< "();" << endl
;
1439 // Try block for a function with exceptions
1440 if (xceptions
.size() > 0) {
1441 out
<< indent() << "try {" << endl
;
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
;
1451 if (!tfunction
->is_oneway() && !tfunction
->get_returntype()->is_void()) {
1452 out
<< "$result->success = ";
1454 out
<< "$this->handler_->" << tfunction
->get_name() << "(";
1456 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
1462 out
<< "$args->" << (*f_iter
)->get_name();
1464 out
<< ");" << endl
;
1466 if (!tfunction
->is_oneway() && xceptions
.size() > 0) {
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() << ") {"
1473 if (!tfunction
->is_oneway()) {
1475 out
<< indent() << "$result->" << (*x_iter
)->get_name() << " = $"
1476 << (*x_iter
)->get_name() << ";" << endl
;
1484 // Shortcut out here for oneway functions
1485 if (tfunction
->is_oneway()) {
1486 out
<< indent() << "return;" << endl
;
1488 out
<< indent() << "}" << endl
;
1492 out
<< indent() << "$bin_accel = ($output instanceof "
1493 << "TBinaryProtocolAccelerated) && function_exists('thrift_protocol_write_binary');"
1496 out
<< indent() << "if ($bin_accel) {" << endl
;
1499 out
<< indent() << "thrift_protocol_write_binary(" << endl
;
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
;
1510 out
<< indent() << ");" << endl
;
1513 out
<< indent() << "} else {" << endl
;
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
;
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
;
1535 out
<< indent() << "}" << endl
;
1539 * Generates helper functions for a service.
1541 * @param tservice The service to generate a header definition for
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
;
1547 ofstream_with_content_based_conditional_update
& f_struct_definition
= f_service_
;
1549 f_struct_definition
<< "// HELPER FUNCTIONS AND STRUCTURES" << endl
<< endl
;
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
);
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
);
1563 generate_php_struct_definition(f_struct_definition
, ts
);
1565 f_struct_definition
.close();
1568 generate_php_function_helpers(tservice
, *f_iter
);
1574 * Generates a struct and helpers for a function.
1576 * @param tfunction The function
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
);
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
);
1593 ofstream_with_content_based_conditional_update
& f_struct_helper
= f_service_
;
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
);
1599 generate_php_struct_definition(f_struct_helper
, &result
, false, true);
1601 f_struct_helper
.close();
1607 * Generates a service interface definition.
1609 * @param tservice The service to generate a header definition for
1611 void t_php_generator::generate_service_interface(t_service
* tservice
) {
1612 ofstream_with_content_based_conditional_update
& f_service_interface
= f_service_
;
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
);
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";
1627 generate_php_doc(f_service_interface
, tservice
);
1628 f_service_interface
<< "interface " << php_namespace_declaration(tservice
) << "If" << extends_if
<< endl
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
;
1639 f_service_interface
<< "}" << endl
;
1641 // Close service interface file
1643 f_service_interface
.close();
1648 * Generates a REST interface
1650 void t_php_generator::generate_service_rest(t_service
* tservice
) {
1651 ofstream_with_content_based_conditional_update
& f_service_rest
= f_service_
;
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
);
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";
1666 f_service_rest
<< "class " << service_name_
<< "Rest" << extends_if
<< endl
1670 if (extends
.empty()) {
1671 f_service_rest
<< indent() << "protected $impl_;" << endl
<< endl
;
1674 f_service_rest
<< indent() << "public function __construct($impl) {" << endl
<< indent()
1675 << " $this->impl_ = $impl;" << endl
<< indent() << "}" << endl
<< endl
;
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
;
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
;
1692 f_service_rest
<< indent() << "$" << (*a_iter
)->get_name() << " = isset(" << req
<< ") ? "
1693 << cast
<< req
<< " : null;" << endl
;
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
;
1711 f_service_rest
<< indent() << "return $this->impl_->" << (*f_iter
)->get_name() << "("
1712 << argument_list((*f_iter
)->get_arglist(), false) << ");" << endl
;
1714 indent(f_service_rest
) << "}" << endl
<< endl
;
1717 f_service_rest
<< "}" << endl
<< endl
;
1719 // Close service rest file
1720 f_service_rest
<< endl
;
1722 f_service_rest
.close();
1727 * Generates a service client definition.
1729 * @param tservice The service to generate a server for.
1731 void t_php_generator::generate_service_client(t_service
* tservice
) {
1732 ofstream_with_content_based_conditional_update
& f_service_client
= f_service_
;
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
);
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
1747 f_service_client
<< "class " << php_namespace_declaration(tservice
) << "Client" << extends_client
1748 << " implements " << php_namespace(tservice
->get_program()) << service_name_
<< "If" << endl
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
;
1759 // Constructor function
1760 f_service_client
<< indent() << "public function __construct($input, $output = null)" << endl
1761 << indent() << "{" << endl
;
1764 if (!extends
.empty()) {
1765 f_service_client
<< indent() << "parent::__construct($input, $output);" << endl
;
1767 f_service_client
<< indent() << "$this->input_ = $input;" << endl
1768 << indent() << "$this->output_ = $output ? $output : $input;" << endl
;
1772 f_service_client
<< indent() << "}" << endl
<< endl
;
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();
1783 f_service_client
<< endl
;
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
<< "(";
1791 for (fld_iter
= fields
.begin(); fld_iter
!= fields
.end(); ++fld_iter
) {
1795 f_service_client
<< ", ";
1797 f_service_client
<< "$" << (*fld_iter
)->get_name();
1799 f_service_client
<< ");" << endl
;
1801 if (!(*f_iter
)->is_oneway()) {
1802 f_service_client
<< indent();
1803 if (!(*f_iter
)->get_returntype()->is_void()) {
1804 f_service_client
<< "return ";
1806 f_service_client
<< "$this->recv_" << funname
<< "();" << endl
;
1808 scope_down(f_service_client
);
1809 f_service_client
<< endl
;
1811 indent(f_service_client
) << "public function send_" << function_signature(*f_iter
) << endl
;
1812 scope_up(f_service_client
);
1814 std::string argsname
= php_namespace(tservice
->get_program()) + service_name_
+ "_"
1815 + (*f_iter
)->get_name() + "_args";
1817 f_service_client
<< indent() << "$args = new " << argsname
<< "();" << endl
;
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
;
1824 f_service_client
<< indent() << "$bin_accel = ($this->output_ instanceof "
1825 << "TBinaryProtocolAccelerated) && function_exists('thrift_protocol_write_binary');"
1828 f_service_client
<< indent() << "if ($bin_accel) {" << endl
;
1831 string messageType
= (*f_iter
)->is_oneway() ? "TMessageType::ONEWAY" : "TMessageType::CALL";
1833 f_service_client
<< indent() << "thrift_protocol_write_binary(" << endl
;
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
;
1844 f_service_client
<< indent() << ");" << endl
;
1847 f_service_client
<< indent() << "} else {" << endl
;
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
;
1857 f_service_client
<< indent() << "$this->output_->writeMessageBegin('" << (*f_iter
)->get_name()
1858 << "', " << messageType
<< ", $this->seqid_);" << endl
;
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
;
1867 f_service_client
<< indent() << "$args->write($this->output_);" << endl
<< indent()
1868 << "$this->output_->writeMessageEnd();" << endl
<< indent()
1869 << "$this->output_->getTransport()->flush();" << endl
;
1872 scope_down(f_service_client
);
1874 scope_down(f_service_client
);
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_
);
1881 t_function
recv_function((*f_iter
)->get_returntype(),
1882 string("recv_") + (*f_iter
)->get_name(),
1885 f_service_client
<< endl
<< indent() << "public function " << function_signature(&recv_function
)
1887 scope_up(f_service_client
);
1889 f_service_client
<< indent() << "$bin_accel = ($this->input_ instanceof "
1890 << "TBinaryProtocolAccelerated)"
1891 << " && function_exists('thrift_protocol_read_binary');" << endl
;
1893 f_service_client
<< indent() << "if ($bin_accel) {" << endl
;
1896 f_service_client
<< indent() << "$result = thrift_protocol_read_binary(" << endl
;
1899 f_service_client
<< indent() << "$this->input_," << endl
1900 << indent() << "'" << resultname
<< "'," << endl
1901 << indent() << "$this->input_->isStrictRead()" << endl
;
1904 f_service_client
<< indent() << ");" << endl
;
1907 f_service_client
<< indent() << "} else {" << endl
;
1910 f_service_client
<< indent() << "$rseqid = 0;" << endl
1911 << indent() << "$fname = null;" << endl
1912 << indent() << "$mtype = 0;" << endl
<< endl
;
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);
1926 f_service_client
<< indent() << "$this->input_->readMessageBegin($fname, $mtype, $rseqid);" << endl
1927 << indent() << "if ($mtype == TMessageType::EXCEPTION) {" << endl
;
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
;
1935 f_service_client
<< indent() << "}" << endl
;
1938 f_service_client
<< indent() << "$result = new " << resultname
<< "();" << endl
1939 << indent() << "$result->read($this->input_);" << endl
;
1941 if (!binary_inline_
) {
1942 f_service_client
<< indent() << "$this->input_->readMessageEnd();" << endl
;
1945 scope_down(f_service_client
);
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
;
1952 f_service_client
<< indent() << "return $result->success;" << endl
;
1955 f_service_client
<< indent() << "}" << endl
;
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
;
1965 f_service_client
<< indent() << "throw $result->" << (*x_iter
)->get_name() << ";" << endl
;
1968 f_service_client
<< indent() << "}" << endl
;
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
;
1975 f_service_client
<< indent() << "throw new \\Exception(\"" << (*f_iter
)->get_name()
1976 << " failed: unknown result\");" << endl
;
1980 scope_down(f_service_client
);
1985 f_service_client
<< "}" << endl
;
1987 // Close service client file
1989 f_service_client
.close();
1994 * Deserializes a field of any type.
1996 void t_php_generator::generate_deserialize_field(ostream
& out
,
2000 t_type
* type
= get_true_type(tfield
->get_type());
2002 if (type
->is_void()) {
2003 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix
+ tfield
->get_name();
2006 string name
= prefix
+ tfield
->get_name();
2008 if (type
->is_struct() || type
->is_xception()) {
2009 generate_deserialize_struct(out
, (t_struct
*)type
, name
);
2012 if (type
->is_container()) {
2013 generate_deserialize_container(out
, type
, name
);
2014 } else if (type
->is_base_type() || type
->is_enum()) {
2016 if (binary_inline_
) {
2017 std::string itrans
= (inclass
? "$this->input_" : "$input");
2019 if (type
->is_base_type()) {
2020 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
2022 case t_base_type::TYPE_VOID
:
2023 throw "compiler error: cannot serialize void field in a struct: " + name
;
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);"
2032 case t_base_type::TYPE_BOOL
:
2033 out
<< indent() << "$" << name
<< " = unpack('c', " << itrans
<< "->readAll(1));"
2034 << endl
<< indent() << "$" << name
<< " = (bool)$" << name
<< "[1];" << endl
;
2036 case t_base_type::TYPE_I8
:
2037 out
<< indent() << "$" << name
<< " = unpack('c', " << itrans
<< "->readAll(1));"
2038 << endl
<< indent() << "$" << name
<< " = $" << name
<< "[1];" << endl
;
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
;
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
;
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
;
2061 case t_base_type::TYPE_DOUBLE
:
2062 out
<< indent() << "$arr = unpack('d', strrev(" << itrans
<< "->readAll(8)));" << endl
2063 << indent() << "$" << name
<< " = $arr[1];" << endl
;
2066 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase
)
2067 + tfield
->get_name();
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
;
2077 indent(out
) << "$xfer += $input->";
2079 if (type
->is_base_type()) {
2080 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
2082 case t_base_type::TYPE_VOID
:
2083 throw "compiler error: cannot serialize void field in a struct: " + name
;
2085 case t_base_type::TYPE_STRING
:
2086 out
<< "readString($" << name
<< ");";
2088 case t_base_type::TYPE_BOOL
:
2089 out
<< "readBool($" << name
<< ");";
2091 case t_base_type::TYPE_I8
:
2092 out
<< "readByte($" << name
<< ");";
2094 case t_base_type::TYPE_I16
:
2095 out
<< "readI16($" << name
<< ");";
2097 case t_base_type::TYPE_I32
:
2098 out
<< "readI32($" << name
<< ");";
2100 case t_base_type::TYPE_I64
:
2101 out
<< "readI64($" << name
<< ");";
2103 case t_base_type::TYPE_DOUBLE
:
2104 out
<< "readDouble($" << name
<< ");";
2107 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase
);
2109 } else if (type
->is_enum()) {
2110 out
<< "readI32($" << name
<< ");";
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());
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.
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
;
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");
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
);
2145 out
<< indent() << "$" << prefix
<< " = array();" << endl
<< indent() << "$" << size
<< " = 0;"
2148 // Declare variables, read header
2149 if (ttype
->is_map()) {
2150 out
<< indent() << "$" << ktype
<< " = 0;" << endl
<< indent() << "$" << vtype
<< " = 0;"
2152 if (binary_inline_
) {
2153 generate_deserialize_field(out
, &fktype
);
2154 generate_deserialize_field(out
, &fvtype
);
2155 generate_deserialize_field(out
, &fsize
);
2157 out
<< indent() << "$xfer += $input->readMapBegin("
2158 << "$" << ktype
<< ", $" << vtype
<< ", $" << size
<< ");" << endl
;
2160 } else if (ttype
->is_set()) {
2161 if (binary_inline_
) {
2162 generate_deserialize_field(out
, &fetype
);
2163 generate_deserialize_field(out
, &fsize
);
2165 out
<< indent() << "$" << etype
<< " = 0;" << endl
<< indent()
2166 << "$xfer += $input->readSetBegin("
2167 << "$" << etype
<< ", $" << size
<< ");" << endl
;
2169 } else if (ttype
->is_list()) {
2170 if (binary_inline_
) {
2171 generate_deserialize_field(out
, &fetype
);
2172 generate_deserialize_field(out
, &fsize
);
2174 out
<< indent() << "$" << etype
<< " = 0;" << endl
<< indent()
2175 << "$xfer += $input->readListBegin("
2176 << "$" << etype
<< ", $" << size
<< ");" << endl
;
2180 // For loop iterates over elements
2181 string i
= tmp("_i");
2182 indent(out
) << "for ($" << i
<< " = 0; $" << i
<< " < $" << size
<< "; ++$" << i
<< ") {" << endl
;
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
);
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
;
2209 * Generates code to deserialize a map
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
);
2217 indent(out
) << declare_field(&fkey
, true, true) << endl
;
2218 indent(out
) << declare_field(&fval
, true, true) << endl
;
2220 generate_deserialize_field(out
, &fkey
);
2221 generate_deserialize_field(out
, &fval
);
2223 indent(out
) << "$" << prefix
<< "[$" << key
<< "] = $" << val
<< ";" << endl
;
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
);
2230 indent(out
) << "$" << elem
<< " = null;" << endl
;
2232 generate_deserialize_field(out
, &felem
);
2234 t_type
* elem_type
= tset
->get_elem_type();
2235 if(php_is_scalar(elem_type
)) {
2236 indent(out
) << "$" << prefix
<< "[$" << elem
<< "] = true;" << endl
;
2238 indent(out
) << "$" << prefix
<< "[] = $" << elem
<< ";" << endl
;
2242 void t_php_generator::generate_deserialize_list_element(ostream
& out
,
2245 string elem
= tmp("elem");
2246 t_field
felem(tlist
->get_elem_type(), elem
);
2248 indent(out
) << "$" << elem
<< " = null;" << endl
;
2250 generate_deserialize_field(out
, &felem
);
2252 indent(out
) << "$" << prefix
<< " []= $" << elem
<< ";" << endl
;
2256 * Serializes a field of any type.
2258 * @param tfield The field to serialize
2259 * @param prefix Name to prepend to field name
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());
2264 // Do nothing for void types
2265 if (type
->is_void()) {
2266 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix
+ tfield
->get_name();
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()) {
2275 string name
= prefix
+ tfield
->get_name();
2277 if (binary_inline_
) {
2278 if (type
->is_base_type()) {
2279 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
2281 case t_base_type::TYPE_VOID
:
2282 throw "compiler error: cannot serialize void field in a struct: " + name
;
2284 case t_base_type::TYPE_STRING
:
2285 out
<< indent() << "$output .= pack('N', strlen($" << name
<< "));" << endl
<< indent()
2286 << "$output .= $" << name
<< ";" << endl
;
2288 case t_base_type::TYPE_BOOL
:
2289 out
<< indent() << "$output .= pack('c', $" << name
<< " ? 1 : 0);" << endl
;
2291 case t_base_type::TYPE_I8
:
2292 out
<< indent() << "$output .= pack('c', $" << name
<< ");" << endl
;
2294 case t_base_type::TYPE_I16
:
2295 out
<< indent() << "$output .= pack('n', $" << name
<< ");" << endl
;
2297 case t_base_type::TYPE_I32
:
2298 out
<< indent() << "$output .= pack('N', $" << name
<< ");" << endl
;
2300 case t_base_type::TYPE_I64
:
2301 out
<< indent() << "$output .= pack('N2', $" << name
<< " >> 32, $" << name
2302 << " & 0xFFFFFFFF);" << endl
;
2304 case t_base_type::TYPE_DOUBLE
:
2305 out
<< indent() << "$output .= strrev(pack('d', $" << name
<< "));" << endl
;
2308 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase
);
2310 } else if (type
->is_enum()) {
2311 out
<< indent() << "$output .= pack('N', $" << name
<< ");" << endl
;
2315 indent(out
) << "$xfer += $output->";
2317 if (type
->is_base_type()) {
2318 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
2320 case t_base_type::TYPE_VOID
:
2321 throw "compiler error: cannot serialize void field in a struct: " + name
;
2323 case t_base_type::TYPE_STRING
:
2324 out
<< "writeString($" << name
<< ");";
2326 case t_base_type::TYPE_BOOL
:
2327 out
<< "writeBool($" << name
<< ");";
2329 case t_base_type::TYPE_I8
:
2330 out
<< "writeByte($" << name
<< ");";
2332 case t_base_type::TYPE_I16
:
2333 out
<< "writeI16($" << name
<< ");";
2335 case t_base_type::TYPE_I32
:
2336 out
<< "writeI32($" << name
<< ");";
2338 case t_base_type::TYPE_I64
:
2339 out
<< "writeI64($" << name
<< ");";
2341 case t_base_type::TYPE_DOUBLE
:
2342 out
<< "writeDouble($" << name
<< ");";
2345 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase
);
2347 } else if (type
->is_enum()) {
2348 out
<< "writeI32($" << name
<< ");";
2353 printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
2355 tfield
->get_name().c_str(),
2356 type
->get_name().c_str());
2361 * Serializes all the members of a struct.
2363 * @param tstruct The struct to serialize
2364 * @param prefix String prefix to attach to all fields
2366 void t_php_generator::generate_serialize_struct(ostream
& out
, t_struct
* tstruct
, string prefix
) {
2368 indent(out
) << "$xfer += $" << prefix
<< "->write($output);" << endl
;
2372 * Writes out a container
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
;
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
;
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
<< ")));"
2393 indent(out
) << "$output->writeSetBegin(" << type_to_enum(((t_set
*)ttype
)->get_elem_type())
2395 << "count($" << prefix
<< "));" << endl
;
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
<< ")));"
2404 indent(out
) << "$output->writeListBegin(" << type_to_enum(((t_list
*)ttype
)->get_elem_type())
2406 << "count($" << prefix
<< "));" << endl
;
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
;
2416 generate_serialize_map_element(out
, (t_map
*)ttype
, kiter
, viter
);
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
;
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
);
2428 generate_serialize_set_element(out
, (t_set
*)ttype
, iter_val
);
2431 } else if (ttype
->is_list()) {
2432 string iter
= tmp("iter");
2433 indent(out
) << "foreach ($" << prefix
<< " as $" << iter
<< ") {" << endl
;
2435 generate_serialize_list_element(out
, (t_list
*)ttype
, iter
);
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
;
2451 * Serializes the members of a map.
2454 void t_php_generator::generate_serialize_map_element(ostream
& out
,
2458 t_field
kfield(tmap
->get_key_type(), kiter
);
2459 generate_serialize_field(out
, &kfield
, "");
2461 t_field
vfield(tmap
->get_val_type(), viter
);
2462 generate_serialize_field(out
, &vfield
, "");
2466 * Serializes the members of a set.
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
, "");
2474 * Serializes the members of a list.
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
, "");
2482 * Emits a PHPDoc comment for the given contents
2484 void t_php_generator::generate_php_docstring_comment(ostream
& out
, string contents
) {
2485 generate_docstring_comment(out
, "/**\n", " * ", contents
, " */\n");
2489 * Emits a PHPDoc comment if the provided object has a doc in Thrift
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());
2498 * Emits a PHPDoc comment for a field
2500 void t_php_generator::generate_php_doc(ostream
& out
, t_field
* field
) {
2503 // prepend free-style doc if available
2504 if (field
->has_doc()) {
2505 ss
<< field
->get_doc() << endl
;
2509 t_type
* type
= get_true_type(field
->get_type());
2510 ss
<< "@var " << type_to_phpdoc(type
) << endl
;
2512 generate_php_docstring_comment(out
, ss
.str());
2516 * Emits a PHPDoc comment for a function
2518 void t_php_generator::generate_php_doc(ostream
& out
, t_function
* function
) {
2520 if (function
->has_doc()) {
2521 ss
<< function
->get_doc() << endl
;
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();
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();
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();
2558 generate_docstring_comment(out
, "/**\n", " * ", ss
.str(), " */\n");
2562 * Declares a field, which may include initialization as necessary.
2564 * @param ttype The type
2566 string
t_php_generator::declare_field(t_field
* tfield
, bool init
, bool obj
) {
2567 string result
= "$" + tfield
->get_name();
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();
2573 case t_base_type::TYPE_VOID
:
2575 case t_base_type::TYPE_STRING
:
2578 case t_base_type::TYPE_BOOL
:
2579 result
+= " = false";
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
:
2587 case t_base_type::TYPE_DOUBLE
:
2591 throw "compiler error: no PHP initializer for base type " + t_base_type::t_base_name(tbase
);
2593 } else if (type
->is_enum()) {
2595 } else if (type
->is_container()) {
2596 result
+= " = array()";
2597 } else if (type
->is_struct() || type
->is_xception()) {
2599 result
+= " = new " + php_namespace(type
->get_program()) + type
->get_name() + "()";
2601 result
+= " = null";
2605 return result
+ ";";
2609 * Renders a function signature of the form 'type name(args)'
2611 * @param tfunction Function definition
2612 * @return String of rendered function definition
2614 string
t_php_generator::function_signature(t_function
* tfunction
, string prefix
) {
2615 return prefix
+ tfunction
->get_name() + "(" + argument_list(tfunction
->get_arglist()) + ")";
2619 * Renders a field list
2621 string
t_php_generator::argument_list(t_struct
* tstruct
, bool addTypeHints
) {
2624 const vector
<t_field
*>& fields
= tstruct
->get_members();
2625 vector
<t_field
*>::const_iterator f_iter
;
2627 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
2634 t_type
* type
= (*f_iter
)->get_type();
2638 if (type
->is_struct()) {
2639 string className
= php_namespace(type
->get_program())
2640 + php_namespace_directory("Definition", false)
2641 + classify(type
->get_name());
2643 result
+= className
+ " ";
2644 } else if (type
->is_container()) {
2649 result
+= "$" + (*f_iter
)->get_name();
2655 * Gets a typecast string for a particular type.
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
:
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
:
2668 case t_base_type::TYPE_DOUBLE
:
2670 case t_base_type::TYPE_STRING
:
2675 } else if (type
->is_enum()) {
2682 * Converts the parse type to a C++ enum string for the given type.
2684 string
t_php_generator::type_to_enum(t_type
* type
) {
2685 type
= get_true_type(type
);
2687 if (type
->is_base_type()) {
2688 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
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";
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";
2719 throw "INVALID TYPE IN type_to_enum: " + type
->get_name();
2723 * Converts the parse type to a PHPDoc string for the given type.
2725 string
t_php_generator::type_to_phpdoc(t_type
* type
) {
2726 type
= get_true_type(type
);
2728 if (type
->is_base_type()) {
2729 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
2731 case t_base_type::TYPE_VOID
:
2733 case t_base_type::TYPE_STRING
:
2735 case t_base_type::TYPE_BOOL
:
2737 case t_base_type::TYPE_I8
:
2739 case t_base_type::TYPE_I16
:
2741 case t_base_type::TYPE_I32
:
2743 case t_base_type::TYPE_I64
:
2745 case t_base_type::TYPE_DOUBLE
:
2748 } else if (type
->is_enum()) {
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()) {
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
) + ")[]";
2760 return type_to_phpdoc(t_elem
) + "[]";
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
) + ")[]";
2768 return type_to_phpdoc(t_elem
) + "[]";
2772 throw "INVALID TYPE IN type_to_enum: " + type
->get_name();
2775 THRIFT_REGISTER_GENERATOR(
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")