1 /*
2  * Copyright 2014 Google Inc. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // independent from idl_parser, since this code is not needed for most clients
18 
19 #include <string>
20 
21 #include "flatbuffers/code_generators.h"
22 #include "flatbuffers/flatbuffers.h"
23 #include "flatbuffers/idl.h"
24 #include "flatbuffers/util.h"
25 
26 namespace flatbuffers {
27 namespace php {
28 // Hardcode spaces per indentation.
29 const std::string Indent = "    ";
30 class PhpGenerator : public BaseGenerator {
31  public:
PhpGenerator(const Parser & parser,const std::string & path,const std::string & file_name)32   PhpGenerator(const Parser &parser, const std::string &path,
33                const std::string &file_name)
34       : BaseGenerator(parser, path, file_name, "\\", "\\") {}
generate()35   bool generate() {
36     if (!GenerateEnums()) return false;
37     if (!GenerateStructs()) return false;
38     return true;
39   }
40 
41  private:
GenerateEnums()42   bool GenerateEnums() {
43     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
44          ++it) {
45       auto &enum_def = **it;
46       std::string enumcode;
47       GenEnum(enum_def, &enumcode);
48       if (!SaveType(enum_def, enumcode, false)) return false;
49     }
50     return true;
51   }
52 
GenerateStructs()53   bool GenerateStructs() {
54     for (auto it = parser_.structs_.vec.begin();
55          it != parser_.structs_.vec.end(); ++it) {
56       auto &struct_def = **it;
57       std::string declcode;
58       GenStruct(struct_def, &declcode);
59       if (!SaveType(struct_def, declcode, true)) return false;
60     }
61     return true;
62   }
63 
64   // Begin by declaring namespace and imports.
BeginFile(const std::string & name_space_name,const bool needs_imports,std::string * code_ptr)65   void BeginFile(const std::string &name_space_name, const bool needs_imports,
66                  std::string *code_ptr) {
67     auto &code = *code_ptr;
68     code += "<?php\n";
69     code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n";
70 
71     if (!name_space_name.empty()) {
72       code += "namespace " + name_space_name + ";\n\n";
73     }
74 
75     if (needs_imports) {
76       code += "use \\Google\\FlatBuffers\\Struct;\n";
77       code += "use \\Google\\FlatBuffers\\Table;\n";
78       code += "use \\Google\\FlatBuffers\\ByteBuffer;\n";
79       code += "use \\Google\\FlatBuffers\\FlatBufferBuilder;\n";
80       code += "\n";
81     }
82   }
83 
84   // Save out the generated code for a Php Table type.
SaveType(const Definition & def,const std::string & classcode,bool needs_imports)85   bool SaveType(const Definition &def, const std::string &classcode,
86                 bool needs_imports) {
87     if (!classcode.length()) return true;
88 
89     std::string code = "";
90     BeginFile(FullNamespace("\\", *def.defined_namespace), needs_imports,
91               &code);
92     code += classcode;
93 
94     std::string filename =
95         NamespaceDir(*def.defined_namespace) + def.name + ".php";
96     return SaveFile(filename.c_str(), code, false);
97   }
98 
99   // Begin a class declaration.
BeginClass(const StructDef & struct_def,std::string * code_ptr)100   static void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
101     std::string &code = *code_ptr;
102     if (struct_def.fixed) {
103       code += "class " + struct_def.name + " extends Struct\n";
104     } else {
105       code += "class " + struct_def.name + " extends Table\n";
106     }
107     code += "{\n";
108   }
109 
EndClass(std::string * code_ptr)110   static void EndClass(std::string *code_ptr) {
111     std::string &code = *code_ptr;
112     code += "}\n";
113   }
114 
115   // Begin enum code with a class declaration.
BeginEnum(const std::string & class_name,std::string * code_ptr)116   static void BeginEnum(const std::string &class_name, std::string *code_ptr) {
117     std::string &code = *code_ptr;
118     code += "class " + class_name + "\n{\n";
119   }
120 
121   // A single enum member.
EnumMember(const EnumDef & enum_def,const EnumVal & ev,std::string * code_ptr)122   static void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
123                          std::string *code_ptr) {
124     std::string &code = *code_ptr;
125     code += Indent + "const ";
126     code += ev.name;
127     code += " = ";
128     code += NumToString(ev.value) + ";\n";
129     (void)enum_def;
130   }
131 
132   // End enum code.
EndEnum(std::string * code_ptr)133   static void EndEnum(std::string *code_ptr) {
134     std::string &code = *code_ptr;
135     code += "}\n";
136   }
137 
138   // Initialize a new struct or table from existing data.
NewRootTypeFromBuffer(const StructDef & struct_def,std::string * code_ptr)139   static void NewRootTypeFromBuffer(const StructDef &struct_def,
140                                     std::string *code_ptr) {
141     std::string &code = *code_ptr;
142 
143     code += Indent + "/**\n";
144     code += Indent + " * @param ByteBuffer $bb\n";
145     code += Indent + " * @return " + struct_def.name + "\n";
146     code += Indent + " */\n";
147     code += Indent + "public static function getRootAs";
148     code += struct_def.name;
149     code += "(ByteBuffer $bb)\n";
150     code += Indent + "{\n";
151 
152     code += Indent + Indent + "$obj = new " + struct_def.name + "();\n";
153     code += Indent + Indent;
154     code += "return ($obj->init($bb->getInt($bb->getPosition())";
155     code += " + $bb->getPosition(), $bb));\n";
156     code += Indent + "}\n\n";
157   }
158 
159   // Initialize an existing object with other data, to avoid an allocation.
InitializeExisting(const StructDef & struct_def,std::string * code_ptr)160   static void InitializeExisting(const StructDef &struct_def,
161                                  std::string *code_ptr) {
162     std::string &code = *code_ptr;
163 
164     code += Indent + "/**\n";
165     code += Indent + " * @param int $_i offset\n";
166     code += Indent + " * @param ByteBuffer $_bb\n";
167     code += Indent + " * @return " + struct_def.name + "\n";
168     code += Indent + " **/\n";
169     code += Indent + "public function init($_i, ByteBuffer $_bb)\n";
170     code += Indent + "{\n";
171     code += Indent + Indent + "$this->bb_pos = $_i;\n";
172     code += Indent + Indent + "$this->bb = $_bb;\n";
173     code += Indent + Indent + "return $this;\n";
174     code += Indent + "}\n\n";
175   }
176 
177   // Get the length of a vector.
GetVectorLen(const FieldDef & field,std::string * code_ptr)178   static void GetVectorLen(const FieldDef &field, std::string *code_ptr) {
179     std::string &code = *code_ptr;
180 
181     code += Indent + "/**\n";
182     code += Indent + " * @return int\n";
183     code += Indent + " */\n";
184     code += Indent + "public function get";
185     code += MakeCamel(field.name) + "Length()\n";
186     code += Indent + "{\n";
187     code += Indent + Indent + "$o = $this->__offset(";
188     code += NumToString(field.value.offset) + ");\n";
189     code += Indent + Indent;
190     code += "return $o != 0 ? $this->__vector_len($o) : 0;\n";
191     code += Indent + "}\n\n";
192   }
193 
194   // Get a [ubyte] vector as a byte array.
GetUByte(const FieldDef & field,std::string * code_ptr)195   static void GetUByte(const FieldDef &field, std::string *code_ptr) {
196     std::string &code = *code_ptr;
197 
198     code += Indent + "/**\n";
199     code += Indent + " * @return string\n";
200     code += Indent + " */\n";
201     code += Indent + "public function get";
202     code += MakeCamel(field.name) + "Bytes()\n";
203     code += Indent + "{\n";
204     code += Indent + Indent + "return $this->__vector_as_bytes(";
205     code += NumToString(field.value.offset) + ");\n";
206     code += Indent + "}\n\n";
207   }
208 
209   // Get the value of a struct's scalar.
GetScalarFieldOfStruct(const FieldDef & field,std::string * code_ptr)210   static void GetScalarFieldOfStruct(const FieldDef &field,
211                                      std::string *code_ptr) {
212     std::string &code = *code_ptr;
213     std::string getter = GenGetter(field.value.type);
214 
215     code += Indent + "/**\n";
216     code += Indent + " * @return ";
217     code += GenTypeGet(field.value.type) + "\n";
218     code += Indent + " */\n";
219     code += Indent + "public function " + getter;
220     code += MakeCamel(field.name) + "()\n";
221     code += Indent + "{\n";
222     code += Indent + Indent + "return ";
223 
224     code += "$this->bb->get";
225     code += MakeCamel(GenTypeGet(field.value.type));
226     code += "($this->bb_pos + ";
227     code += NumToString(field.value.offset) + ")";
228     code += ";\n";
229 
230     code += Indent + "}\n\n";
231   }
232 
233   // Get the value of a table's scalar.
GetScalarFieldOfTable(const FieldDef & field,std::string * code_ptr)234   void GetScalarFieldOfTable(const FieldDef &field, std::string *code_ptr) {
235     std::string &code = *code_ptr;
236     std::string getter = GenGetter(field.value.type);
237 
238     code += Indent + "/**\n";
239     code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
240     code += Indent + " */\n";
241     code += Indent + "public function get";
242     code += MakeCamel(field.name);
243     code += "()\n";
244     code += Indent + "{\n";
245     code += Indent + Indent + "$o = $this->__offset(" +
246             NumToString(field.value.offset) + ");\n" + Indent + Indent +
247             "return $o != 0 ? ";
248     code += "$this->bb->get";
249     code += MakeCamel(GenTypeGet(field.value.type)) + "($o + $this->bb_pos)";
250     code += " : " + GenDefaultValue(field.value) + ";\n";
251     code += Indent + "}\n\n";
252   }
253 
254   // Get a struct by initializing an existing struct.
255   // Specific to Struct.
GetStructFieldOfStruct(const FieldDef & field,std::string * code_ptr)256   void GetStructFieldOfStruct(const FieldDef &field, std::string *code_ptr) {
257     std::string &code = *code_ptr;
258 
259     code += Indent + "/**\n";
260     code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
261     code += Indent + " */\n";
262     code += Indent + "public function get";
263     code += MakeCamel(field.name) + "()\n";
264     code += Indent + "{\n";
265     code += Indent + Indent + "$obj = new ";
266     code += GenTypeGet(field.value.type) + "();\n";
267     code += Indent + Indent + "$obj->init($this->bb_pos + ";
268     code += NumToString(field.value.offset) + ", $this->bb);";
269     code += "\n" + Indent + Indent + "return $obj;\n";
270     code += Indent + "}\n\n";
271   }
272 
273   // Get a struct by initializing an existing struct.
274   // Specific to Table.
GetStructFieldOfTable(const FieldDef & field,std::string * code_ptr)275   void GetStructFieldOfTable(const FieldDef &field, std::string *code_ptr) {
276     std::string &code = *code_ptr;
277 
278     code += Indent + "public function get";
279     code += MakeCamel(field.name);
280     code += "()\n";
281     code += Indent + "{\n";
282     code += Indent + Indent + "$obj = new ";
283     code += MakeCamel(GenTypeGet(field.value.type)) + "();\n";
284     code += Indent + Indent + "$o = $this->__offset(" +
285             NumToString(field.value.offset) + ");\n";
286     code += Indent + Indent;
287     code += "return $o != 0 ? $obj->init(";
288     if (field.value.type.struct_def->fixed) {
289       code += "$o + $this->bb_pos, $this->bb) : ";
290     } else {
291       code += "$this->__indirect($o + $this->bb_pos), $this->bb) : ";
292     }
293     code += GenDefaultValue(field.value) + ";\n";
294     code += Indent + "}\n\n";
295   }
296 
297   // Get the value of a string.
GetStringField(const FieldDef & field,std::string * code_ptr)298   void GetStringField(const FieldDef &field, std::string *code_ptr) {
299     std::string &code = *code_ptr;
300     code += Indent + "public function get";
301     code += MakeCamel(field.name);
302     code += "()\n";
303     code += Indent + "{\n";
304     code += Indent + Indent + "$o = $this->__offset(" +
305             NumToString(field.value.offset) + ");\n";
306     code += Indent + Indent;
307     code += "return $o != 0 ? $this->__string($o + $this->bb_pos) : ";
308     code += GenDefaultValue(field.value) + ";\n";
309     code += Indent + "}\n\n";
310   }
311 
312   // Get the value of a union from an object.
GetUnionField(const FieldDef & field,std::string * code_ptr)313   void GetUnionField(const FieldDef &field, std::string *code_ptr) {
314     std::string &code = *code_ptr;
315 
316     code += Indent + "/**\n";
317     code += Indent + " * @return" + GenTypeBasic(field.value.type) + "\n";
318     code += Indent + " */\n";
319     code += Indent + "public function get";
320     code += MakeCamel(field.name) + "($obj)\n";
321     code += Indent + "{\n";
322     code += Indent + Indent + "$o = $this->__offset(" +
323             NumToString(field.value.offset) + ");\n";
324     code += Indent + Indent;
325     code += "return $o != 0 ? $this->__union($obj, $o) : null;\n";
326     code += Indent + "}\n\n";
327   }
328 
329   // Get the value of a vector's struct member.
GetMemberOfVectorOfStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)330   void GetMemberOfVectorOfStruct(const StructDef &struct_def,
331                                  const FieldDef &field, std::string *code_ptr) {
332     std::string &code = *code_ptr;
333     auto vectortype = field.value.type.VectorType();
334 
335     code += Indent + "/**\n";
336     code += Indent + " * @return" + GenTypeBasic(field.value.type) + "\n";
337     code += Indent + " */\n";
338     code += Indent + "public function get";
339     code += MakeCamel(field.name);
340     code += "($j)\n";
341     code += Indent + "{\n";
342     code += Indent + Indent + "$o = $this->__offset(" +
343             NumToString(field.value.offset) + ");\n";
344     code += Indent + Indent + "$obj = new ";
345     code += MakeCamel(GenTypeGet(field.value.type)) + "();\n";
346 
347     switch (field.value.type.base_type) {
348       case BASE_TYPE_STRUCT:
349         if (struct_def.fixed) {
350           code += Indent + Indent;
351           code += "return $o != 0 ? $obj->init($this->bb_pos +" +
352                   NumToString(field.value.offset) + ", $this->bb) : null;\n";
353         } else {
354           code += Indent + Indent + "return $o != 0 ? $obj->init(";
355           code += field.value.type.struct_def->fixed
356                       ? "$o + $this->bb_pos"
357                       : "$this->__indirect($o + $this->bb_pos)";
358           code += ", $this->bb) : null;\n";
359         }
360         break;
361       case BASE_TYPE_STRING:
362         code += "// base_type_string\n";
363         // TODO(chobie): do we need this?
364         break;
365       case BASE_TYPE_VECTOR:
366         if (vectortype.base_type == BASE_TYPE_STRUCT) {
367           code += Indent + Indent + "return $o != 0 ? $obj->init(";
368           if (vectortype.struct_def->fixed) {
369             code += "$this->__vector($o) + $j *";
370             code += NumToString(InlineSize(vectortype));
371           } else {
372             code += "$this->__indirect($this->__vector($o) + $j * ";
373             code += NumToString(InlineSize(vectortype)) + ")";
374           }
375           code += ", $this->bb) : null;\n";
376         }
377         break;
378       case BASE_TYPE_UNION:
379         code += Indent + Indent + "return $o != 0 ? $this->";
380         code += GenGetter(field.value.type) + "($obj, $o); null;\n";
381         break;
382       default: break;
383     }
384 
385     code += Indent + "}\n\n";
386   }
387 
388   // Get the value of a vector's non-struct member. Uses a named return
389   // argument to conveniently set the zero value for the result.
GetMemberOfVectorOfNonStruct(const FieldDef & field,std::string * code_ptr)390   void GetMemberOfVectorOfNonStruct(const FieldDef &field,
391                                     std::string *code_ptr) {
392     std::string &code = *code_ptr;
393     auto vectortype = field.value.type.VectorType();
394 
395     code += Indent + "/**\n";
396     code += Indent + " * @param int offset\n";
397     code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
398     code += Indent + " */\n";
399     code += Indent + "public function get";
400     code += MakeCamel(field.name);
401     code += "($j)\n";
402     code += Indent + "{\n";
403     code += Indent + Indent + "$o = $this->__offset(" +
404             NumToString(field.value.offset) + ");\n";
405 
406     if (field.value.type.VectorType().base_type == BASE_TYPE_STRING) {
407       code += Indent + Indent;
408       code += "return $o != 0 ? $this->__string($this->__vector($o) + $j * ";
409       code += NumToString(InlineSize(vectortype)) + ") : ";
410       code += GenDefaultValue(field.value) + ";\n";
411     } else {
412       code += Indent + Indent + "return $o != 0 ? $this->bb->get";
413       code += MakeCamel(GenTypeGet(field.value.type));
414       code += "($this->__vector($o) + $j * ";
415       code += NumToString(InlineSize(vectortype)) + ") : ";
416       code += GenDefaultValue(field.value) + ";\n";
417     }
418     code += Indent + "}\n\n";
419   }
420 
421   // Get the value of a vector's union member. Uses a named return
422   // argument to conveniently set the zero value for the result.
GetMemberOfVectorOfUnion(const FieldDef & field,std::string * code_ptr)423   void GetMemberOfVectorOfUnion(const FieldDef &field, std::string *code_ptr) {
424     std::string &code = *code_ptr;
425     auto vectortype = field.value.type.VectorType();
426 
427     code += Indent + "/**\n";
428     code += Indent + " * @param int offset\n";
429     code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
430     code += Indent + " */\n";
431     code += Indent + "public function get";
432     code += MakeCamel(field.name);
433     code += "($j, $obj)\n";
434     code += Indent + "{\n";
435     code += Indent + Indent + "$o = $this->__offset(" +
436             NumToString(field.value.offset) + ");\n";
437     code += Indent + Indent + "return $o != 0 ? ";
438     code += "$this->__union($obj, $this->__vector($o) + $j * ";
439     code += NumToString(InlineSize(vectortype)) + " - $this->bb_pos) : null;\n";
440     code += Indent + "}\n\n";
441   }
442 
443   // Recursively generate arguments for a constructor, to deal with nested
444   // structs.
StructBuilderArgs(const StructDef & struct_def,const char * nameprefix,std::string * code_ptr)445   static void StructBuilderArgs(const StructDef &struct_def,
446                                 const char *nameprefix, std::string *code_ptr) {
447     for (auto it = struct_def.fields.vec.begin();
448          it != struct_def.fields.vec.end(); ++it) {
449       auto &field = **it;
450       if (IsStruct(field.value.type)) {
451         // Generate arguments for a struct inside a struct. To ensure names
452         // don't clash, and to make it obvious
453         // these arguments are constructing
454         // a nested struct, prefix the name with the field name.
455         StructBuilderArgs(*field.value.type.struct_def,
456                           (nameprefix + (field.name + "_")).c_str(), code_ptr);
457       } else {
458         std::string &code = *code_ptr;
459         code += std::string(", $") + nameprefix;
460         code += MakeCamel(field.name, false);
461       }
462     }
463   }
464 
465   // Recursively generate struct construction statements and instert manual
466   // padding.
StructBuilderBody(const StructDef & struct_def,const char * nameprefix,std::string * code_ptr)467   static void StructBuilderBody(const StructDef &struct_def,
468                                 const char *nameprefix, std::string *code_ptr) {
469     std::string &code = *code_ptr;
470     code += Indent + Indent + "$builder->prep(";
471     code += NumToString(struct_def.minalign) + ", ";
472     code += NumToString(struct_def.bytesize) + ");\n";
473     for (auto it = struct_def.fields.vec.rbegin();
474          it != struct_def.fields.vec.rend(); ++it) {
475       auto &field = **it;
476       if (field.padding) {
477         code += Indent + Indent + "$builder->pad(";
478         code += NumToString(field.padding) + ");\n";
479       }
480       if (IsStruct(field.value.type)) {
481         StructBuilderBody(*field.value.type.struct_def,
482                           (nameprefix + (field.name + "_")).c_str(), code_ptr);
483       } else {
484         code += Indent + Indent + "$builder->put" + GenMethod(field) + "($";
485         code += nameprefix + MakeCamel(field.name, false) + ");\n";
486       }
487     }
488   }
489 
490   // Get the value of a table's starting offset.
GetStartOfTable(const StructDef & struct_def,std::string * code_ptr)491   static void GetStartOfTable(const StructDef &struct_def,
492                               std::string *code_ptr) {
493     std::string &code = *code_ptr;
494 
495     code += Indent + "/**\n";
496     code += Indent + " * @param FlatBufferBuilder $builder\n";
497     code += Indent + " * @return void\n";
498     code += Indent + " */\n";
499     code += Indent + "public static function start" + struct_def.name;
500     code += "(FlatBufferBuilder $builder)\n";
501     code += Indent + "{\n";
502     code += Indent + Indent + "$builder->StartObject(";
503     code += NumToString(struct_def.fields.vec.size());
504     code += ");\n";
505     code += Indent + "}\n\n";
506 
507     code += Indent + "/**\n";
508     code += Indent + " * @param FlatBufferBuilder $builder\n";
509     code += Indent + " * @return " + struct_def.name + "\n";
510     code += Indent + " */\n";
511     code += Indent + "public static function create" + struct_def.name;
512     code += "(FlatBufferBuilder $builder, ";
513 
514     for (auto it = struct_def.fields.vec.begin();
515          it != struct_def.fields.vec.end(); ++it) {
516       auto &field = **it;
517 
518       if (field.deprecated) continue;
519       code += "$" + field.name;
520       if (!(it == (--struct_def.fields.vec.end()))) { code += ", "; }
521     }
522     code += ")\n";
523     code += Indent + "{\n";
524     code += Indent + Indent + "$builder->startObject(";
525     code += NumToString(struct_def.fields.vec.size());
526     code += ");\n";
527     for (auto it = struct_def.fields.vec.begin();
528          it != struct_def.fields.vec.end(); ++it) {
529       auto &field = **it;
530       if (field.deprecated) continue;
531 
532       code += Indent + Indent + "self::add";
533       code += MakeCamel(field.name) + "($builder, $" + field.name + ");\n";
534     }
535 
536     code += Indent + Indent + "$o = $builder->endObject();\n";
537 
538     for (auto it = struct_def.fields.vec.begin();
539          it != struct_def.fields.vec.end(); ++it) {
540       auto &field = **it;
541       if (!field.deprecated && field.required) {
542         code += Indent + Indent + "$builder->required($o, ";
543         code += NumToString(field.value.offset);
544         code += ");  // " + field.name + "\n";
545       }
546     }
547     code += Indent + Indent + "return $o;\n";
548     code += Indent + "}\n\n";
549   }
550 
551   // Set the value of a table's field.
BuildFieldOfTable(const FieldDef & field,const size_t offset,std::string * code_ptr)552   static void BuildFieldOfTable(const FieldDef &field, const size_t offset,
553                                 std::string *code_ptr) {
554     std::string &code = *code_ptr;
555 
556     code += Indent + "/**\n";
557     code += Indent + " * @param FlatBufferBuilder $builder\n";
558     code += Indent + " * @param " + GenTypeBasic(field.value.type) + "\n";
559     code += Indent + " * @return void\n";
560     code += Indent + " */\n";
561     code += Indent + "public static function ";
562     code += "add" + MakeCamel(field.name);
563     code += "(FlatBufferBuilder $builder, ";
564     code += "$" + MakeCamel(field.name, false);
565     code += ")\n";
566     code += Indent + "{\n";
567     code += Indent + Indent + "$builder->add";
568     code += GenMethod(field) + "X(";
569     code += NumToString(offset) + ", ";
570 
571     code += "$" + MakeCamel(field.name, false);
572     code += ", ";
573 
574     if (field.value.type.base_type == BASE_TYPE_BOOL) {
575       code += "false";
576     } else {
577       code += field.value.constant;
578     }
579     code += ");\n";
580     code += Indent + "}\n\n";
581   }
582 
583   // Set the value of one of the members of a table's vector.
BuildVectorOfTable(const FieldDef & field,std::string * code_ptr)584   static void BuildVectorOfTable(const FieldDef &field, std::string *code_ptr) {
585     std::string &code = *code_ptr;
586 
587     auto vector_type = field.value.type.VectorType();
588     auto alignment = InlineAlignment(vector_type);
589     auto elem_size = InlineSize(vector_type);
590     code += Indent + "/**\n";
591     code += Indent + " * @param FlatBufferBuilder $builder\n";
592     code += Indent + " * @param array offset array\n";
593     code += Indent + " * @return int vector offset\n";
594     code += Indent + " */\n";
595     code += Indent + "public static function create";
596     code += MakeCamel(field.name);
597     code += "Vector(FlatBufferBuilder $builder, array $data)\n";
598     code += Indent + "{\n";
599     code += Indent + Indent + "$builder->startVector(";
600     code += NumToString(elem_size);
601     code += ", count($data), " + NumToString(alignment);
602     code += ");\n";
603     code += Indent + Indent;
604     code += "for ($i = count($data) - 1; $i >= 0; $i--) {\n";
605     if (IsScalar(field.value.type.VectorType().base_type)) {
606       code += Indent + Indent + Indent;
607       code += "$builder->put";
608       code += MakeCamel(GenTypeBasic(field.value.type.VectorType()));
609       code += "($data[$i]);\n";
610     } else {
611       code += Indent + Indent + Indent;
612       code += "$builder->putOffset($data[$i]);\n";
613     }
614     code += Indent + Indent + "}\n";
615     code += Indent + Indent + "return $builder->endVector();\n";
616     code += Indent + "}\n\n";
617 
618     code += Indent + "/**\n";
619     code += Indent + " * @param FlatBufferBuilder $builder\n";
620     code += Indent + " * @param int $numElems\n";
621     code += Indent + " * @return void\n";
622     code += Indent + " */\n";
623     code += Indent + "public static function start";
624     code += MakeCamel(field.name);
625     code += "Vector(FlatBufferBuilder $builder, $numElems)\n";
626     code += Indent + "{\n";
627     code += Indent + Indent + "$builder->startVector(";
628     code += NumToString(elem_size);
629     code += ", $numElems, " + NumToString(alignment);
630     code += ");\n";
631     code += Indent + "}\n\n";
632   }
633 
634   // Get the offset of the end of a table.
GetEndOffsetOnTable(const StructDef & struct_def,std::string * code_ptr)635   void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
636     std::string &code = *code_ptr;
637 
638     code += Indent + "/**\n";
639     code += Indent + " * @param FlatBufferBuilder $builder\n";
640     code += Indent + " * @return int table offset\n";
641     code += Indent + " */\n";
642     code += Indent + "public static function end" + struct_def.name;
643     code += "(FlatBufferBuilder $builder)\n";
644     code += Indent + "{\n";
645     code += Indent + Indent + "$o = $builder->endObject();\n";
646 
647     for (auto it = struct_def.fields.vec.begin();
648          it != struct_def.fields.vec.end(); ++it) {
649       auto &field = **it;
650       if (!field.deprecated && field.required) {
651         code += Indent + Indent + "$builder->required($o, ";
652         code += NumToString(field.value.offset);
653         code += ");  // " + field.name + "\n";
654       }
655     }
656     code += Indent + Indent + "return $o;\n";
657     code += Indent + "}\n";
658 
659     if (parser_.root_struct_def_ == &struct_def) {
660       code += "\n";
661       code += Indent + "public static function finish";
662       code += struct_def.name;
663       code += "Buffer(FlatBufferBuilder $builder, $offset)\n";
664       code += Indent + "{\n";
665       code += Indent + Indent + "$builder->finish($offset";
666 
667       if (parser_.file_identifier_.length())
668         code += ", \"" + parser_.file_identifier_ + "\"";
669       code += ");\n";
670       code += Indent + "}\n";
671     }
672   }
673 
674   // Generate a struct field, conditioned on its child type(s).
GenStructAccessor(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)675   void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
676                          std::string *code_ptr) {
677     GenComment(field.doc_comment, code_ptr, nullptr);
678 
679     if (IsScalar(field.value.type.base_type)) {
680       if (struct_def.fixed) {
681         GetScalarFieldOfStruct(field, code_ptr);
682       } else {
683         GetScalarFieldOfTable(field, code_ptr);
684       }
685     } else {
686       switch (field.value.type.base_type) {
687         case BASE_TYPE_STRUCT:
688           if (struct_def.fixed) {
689             GetStructFieldOfStruct(field, code_ptr);
690           } else {
691             GetStructFieldOfTable(field, code_ptr);
692           }
693           break;
694         case BASE_TYPE_STRING: GetStringField(field, code_ptr); break;
695         case BASE_TYPE_VECTOR: {
696           auto vectortype = field.value.type.VectorType();
697           if (vectortype.base_type == BASE_TYPE_UNION) {
698             GetMemberOfVectorOfUnion(field, code_ptr);
699           } else if (vectortype.base_type == BASE_TYPE_STRUCT) {
700             GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
701           } else {
702             GetMemberOfVectorOfNonStruct(field, code_ptr);
703           }
704           break;
705         }
706         case BASE_TYPE_UNION: GetUnionField(field, code_ptr); break;
707         default: FLATBUFFERS_ASSERT(0);
708       }
709     }
710     if (field.value.type.base_type == BASE_TYPE_VECTOR) {
711       GetVectorLen(field, code_ptr);
712       if (field.value.type.element == BASE_TYPE_UCHAR) {
713         GetUByte(field, code_ptr);
714       }
715     }
716   }
717 
718   // Generate table constructors, conditioned on its members' types.
GenTableBuilders(const StructDef & struct_def,std::string * code_ptr)719   void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
720     GetStartOfTable(struct_def, code_ptr);
721 
722     for (auto it = struct_def.fields.vec.begin();
723          it != struct_def.fields.vec.end(); ++it) {
724       auto &field = **it;
725       if (field.deprecated) continue;
726 
727       auto offset = it - struct_def.fields.vec.begin();
728       if (field.value.type.base_type == BASE_TYPE_UNION) {
729         std::string &code = *code_ptr;
730         code += Indent + "public static function add";
731         code += MakeCamel(field.name);
732         code += "(FlatBufferBuilder $builder, $offset)\n";
733         code += Indent + "{\n";
734         code += Indent + Indent + "$builder->addOffsetX(";
735         code += NumToString(offset) + ", $offset, 0);\n";
736         code += Indent + "}\n\n";
737       } else {
738         BuildFieldOfTable(field, offset, code_ptr);
739       }
740       if (field.value.type.base_type == BASE_TYPE_VECTOR) {
741         BuildVectorOfTable(field, code_ptr);
742       }
743     }
744 
745     GetEndOffsetOnTable(struct_def, code_ptr);
746   }
747 
748   // Generate struct or table methods.
GenStruct(const StructDef & struct_def,std::string * code_ptr)749   void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
750     if (struct_def.generated) return;
751 
752     GenComment(struct_def.doc_comment, code_ptr, nullptr);
753     BeginClass(struct_def, code_ptr);
754 
755     if (!struct_def.fixed) {
756       // Generate a special accessor for the table that has been declared as
757       // the root type.
758       NewRootTypeFromBuffer(struct_def, code_ptr);
759     }
760 
761     std::string &code = *code_ptr;
762     if (!struct_def.fixed) {
763       if (parser_.file_identifier_.length()) {
764         // Return the identifier
765         code += Indent + "public static function " + struct_def.name;
766         code += "Identifier()\n";
767         code += Indent + "{\n";
768         code += Indent + Indent + "return \"";
769         code += parser_.file_identifier_ + "\";\n";
770         code += Indent + "}\n\n";
771 
772         // Check if a buffer has the identifier.
773         code += Indent + "public static function " + struct_def.name;
774         code += "BufferHasIdentifier(ByteBuffer $buf)\n";
775         code += Indent + "{\n";
776         code += Indent + Indent + "return self::";
777         code += "__has_identifier($buf, self::";
778         code += struct_def.name + "Identifier());\n";
779         code += Indent + "}\n\n";
780       }
781 
782       if (parser_.file_extension_.length()) {
783         // Return the extension
784         code += Indent + "public static function " + struct_def.name;
785         code += "Extension()\n";
786         code += Indent + "{\n";
787         code += Indent + Indent + "return \"" + parser_.file_extension_;
788         code += "\";\n";
789         code += Indent + "}\n\n";
790       }
791     }
792 
793     // Generate the Init method that sets the field in a pre-existing
794     // accessor object. This is to allow object reuse.
795     InitializeExisting(struct_def, code_ptr);
796     for (auto it = struct_def.fields.vec.begin();
797          it != struct_def.fields.vec.end(); ++it) {
798       auto &field = **it;
799       if (field.deprecated) continue;
800 
801       GenStructAccessor(struct_def, field, code_ptr);
802     }
803 
804     if (struct_def.fixed) {
805       // create a struct constructor function
806       GenStructBuilder(struct_def, code_ptr);
807     } else {
808       // Create a set of functions that allow table construction.
809       GenTableBuilders(struct_def, code_ptr);
810     }
811     EndClass(code_ptr);
812   }
813 
814   // Generate enum declarations.
GenEnum(const EnumDef & enum_def,std::string * code_ptr)815   static void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
816     if (enum_def.generated) return;
817 
818     GenComment(enum_def.doc_comment, code_ptr, nullptr);
819     BeginEnum(enum_def.name, code_ptr);
820     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
821       auto &ev = **it;
822       GenComment(ev.doc_comment, code_ptr, nullptr);
823       EnumMember(enum_def, ev, code_ptr);
824     }
825 
826     std::string &code = *code_ptr;
827     code += "\n";
828     code += Indent + "private static $names = array(\n";
829     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
830       auto &ev = **it;
831       code += Indent + Indent + enum_def.name + "::" + ev.name + "=>" + "\"" + ev.name + "\",\n";
832     }
833 
834     code += Indent + ");\n\n";
835     code += Indent + "public static function Name($e)\n";
836     code += Indent + "{\n";
837     code += Indent + Indent + "if (!isset(self::$names[$e])) {\n";
838     code += Indent + Indent + Indent + "throw new \\Exception();\n";
839     code += Indent + Indent + "}\n";
840     code += Indent + Indent + "return self::$names[$e];\n";
841     code += Indent + "}\n";
842     EndEnum(code_ptr);
843   }
844 
845   // Returns the function name that is able to read a value of the given type.
GenGetter(const Type & type)846   static std::string GenGetter(const Type &type) {
847     switch (type.base_type) {
848       case BASE_TYPE_STRING: return "__string";
849       case BASE_TYPE_STRUCT: return "__struct";
850       case BASE_TYPE_UNION: return "__union";
851       case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
852       default: return "Get";
853     }
854   }
855 
856   // Returns the method name for use with add/put calls.
GenMethod(const FieldDef & field)857   static std::string GenMethod(const FieldDef &field) {
858     return IsScalar(field.value.type.base_type)
859                ? MakeCamel(GenTypeBasic(field.value.type))
860                : (IsStruct(field.value.type) ? "Struct" : "Offset");
861   }
862 
GenTypeBasic(const Type & type)863   static std::string GenTypeBasic(const Type &type) {
864     static const char *ctypename[] = {
865     // clang-format off
866         #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
867             CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \
868             #NTYPE,
869                 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
870         #undef FLATBUFFERS_TD
871       // clang-format on
872     };
873     return ctypename[type.base_type];
874   }
875 
GenDefaultValue(const Value & value)876   std::string GenDefaultValue(const Value &value) {
877     if (value.type.enum_def) {
878       if (auto val = value.type.enum_def->ReverseLookup(
879               StringToInt(value.constant.c_str()), false)) {
880         return WrapInNameSpace(*value.type.enum_def) + "::" + val->name;
881       }
882     }
883 
884     switch (value.type.base_type) {
885       case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
886 
887       case BASE_TYPE_STRING: return "null";
888 
889       case BASE_TYPE_LONG:
890       case BASE_TYPE_ULONG:
891         if (value.constant != "0") {
892           int64_t constant = StringToInt(value.constant.c_str());
893           return NumToString(constant);
894         }
895         return "0";
896 
897       default: return value.constant;
898     }
899   }
900 
GenTypePointer(const Type & type)901   static std::string GenTypePointer(const Type &type) {
902     switch (type.base_type) {
903       case BASE_TYPE_STRING: return "string";
904       case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
905       case BASE_TYPE_STRUCT: return type.struct_def->name;
906       case BASE_TYPE_UNION:
907         // fall through
908       default: return "Table";
909     }
910   }
911 
GenTypeGet(const Type & type)912   static std::string GenTypeGet(const Type &type) {
913     return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
914   }
915 
916   // Create a struct with a builder and the struct's arguments.
GenStructBuilder(const StructDef & struct_def,std::string * code_ptr)917   static void GenStructBuilder(const StructDef &struct_def,
918                                std::string *code_ptr) {
919     std::string &code = *code_ptr;
920     code += "\n";
921     code += Indent + "/**\n";
922     code += Indent + " * @return int offset\n";
923     code += Indent + " */\n";
924     code += Indent + "public static function create" + struct_def.name;
925     code += "(FlatBufferBuilder $builder";
926     StructBuilderArgs(struct_def, "", code_ptr);
927     code += ")\n";
928     code += Indent + "{\n";
929 
930     StructBuilderBody(struct_def, "", code_ptr);
931 
932     code += Indent + Indent + "return $builder->offset();\n";
933     code += Indent + "}\n";
934   }
935 };
936 }  // namespace php
937 
GeneratePhp(const Parser & parser,const std::string & path,const std::string & file_name)938 bool GeneratePhp(const Parser &parser, const std::string &path,
939                  const std::string &file_name) {
940   php::PhpGenerator generator(parser, path, file_name);
941   return generator.generate();
942 }
943 }  // namespace flatbuffers
944