• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 EnumVal ev,std::string * code_ptr)122   static void EnumMember(const EnumVal ev, std::string *code_ptr) {
123     std::string &code = *code_ptr;
124     code += Indent + "const ";
125     code += ev.name;
126     code += " = ";
127     code += NumToString(ev.value) + ";\n";
128   }
129 
130   // End enum code.
EndEnum(std::string * code_ptr)131   static void EndEnum(std::string *code_ptr) {
132     std::string &code = *code_ptr;
133     code += "}\n";
134   }
135 
136   // Initialize a new struct or table from existing data.
NewRootTypeFromBuffer(const StructDef & struct_def,std::string * code_ptr)137   static void NewRootTypeFromBuffer(const StructDef &struct_def,
138                                     std::string *code_ptr) {
139     std::string &code = *code_ptr;
140 
141     code += Indent + "/**\n";
142     code += Indent + " * @param ByteBuffer $bb\n";
143     code += Indent + " * @return " + struct_def.name + "\n";
144     code += Indent + " */\n";
145     code += Indent + "public static function getRootAs";
146     code += struct_def.name;
147     code += "(ByteBuffer $bb)\n";
148     code += Indent + "{\n";
149 
150     code += Indent + Indent + "$obj = new " + struct_def.name + "();\n";
151     code += Indent + Indent;
152     code += "return ($obj->init($bb->getInt($bb->getPosition())";
153     code += " + $bb->getPosition(), $bb));\n";
154     code += Indent + "}\n\n";
155   }
156 
157   // Initialize an existing object with other data, to avoid an allocation.
InitializeExisting(const StructDef & struct_def,std::string * code_ptr)158   static void InitializeExisting(const StructDef &struct_def,
159                                  std::string *code_ptr) {
160     std::string &code = *code_ptr;
161 
162     code += Indent + "/**\n";
163     code += Indent + " * @param int $_i offset\n";
164     code += Indent + " * @param ByteBuffer $_bb\n";
165     code += Indent + " * @return " + struct_def.name + "\n";
166     code += Indent + " **/\n";
167     code += Indent + "public function init($_i, ByteBuffer $_bb)\n";
168     code += Indent + "{\n";
169     code += Indent + Indent + "$this->bb_pos = $_i;\n";
170     code += Indent + Indent + "$this->bb = $_bb;\n";
171     code += Indent + Indent + "return $this;\n";
172     code += Indent + "}\n\n";
173   }
174 
175   // Get the length of a vector.
GetVectorLen(const FieldDef & field,std::string * code_ptr)176   static void GetVectorLen(const FieldDef &field, std::string *code_ptr) {
177     std::string &code = *code_ptr;
178 
179     code += Indent + "/**\n";
180     code += Indent + " * @return int\n";
181     code += Indent + " */\n";
182     code += Indent + "public function get";
183     code += MakeCamel(field.name) + "Length()\n";
184     code += Indent + "{\n";
185     code += Indent + Indent + "$o = $this->__offset(";
186     code += NumToString(field.value.offset) + ");\n";
187     code += Indent + Indent;
188     code += "return $o != 0 ? $this->__vector_len($o) : 0;\n";
189     code += Indent + "}\n\n";
190   }
191 
192   // Get a [ubyte] vector as a byte array.
GetUByte(const FieldDef & field,std::string * code_ptr)193   static void GetUByte(const FieldDef &field, std::string *code_ptr) {
194     std::string &code = *code_ptr;
195 
196     code += Indent + "/**\n";
197     code += Indent + " * @return string\n";
198     code += Indent + " */\n";
199     code += Indent + "public function get";
200     code += MakeCamel(field.name) + "Bytes()\n";
201     code += Indent + "{\n";
202     code += Indent + Indent + "return $this->__vector_as_bytes(";
203     code += NumToString(field.value.offset) + ");\n";
204     code += Indent + "}\n\n";
205   }
206 
207   // Get the value of a struct's scalar.
GetScalarFieldOfStruct(const FieldDef & field,std::string * code_ptr)208   static void GetScalarFieldOfStruct(const FieldDef &field,
209                                      std::string *code_ptr) {
210     std::string &code = *code_ptr;
211     std::string getter = GenGetter(field.value.type);
212 
213     code += Indent + "/**\n";
214     code += Indent + " * @return ";
215     code += GenTypeGet(field.value.type) + "\n";
216     code += Indent + " */\n";
217     code += Indent + "public function " + getter;
218     code += MakeCamel(field.name) + "()\n";
219     code += Indent + "{\n";
220     code += Indent + Indent + "return ";
221 
222     code += "$this->bb->get";
223     code += MakeCamel(GenTypeGet(field.value.type));
224     code += "($this->bb_pos + ";
225     code += NumToString(field.value.offset) + ")";
226     code += ";\n";
227 
228     code += Indent + "}\n\n";
229   }
230 
231   // Get the value of a table's scalar.
GetScalarFieldOfTable(const FieldDef & field,std::string * code_ptr)232   void GetScalarFieldOfTable(const FieldDef &field, std::string *code_ptr) {
233     std::string &code = *code_ptr;
234     std::string getter = GenGetter(field.value.type);
235 
236     code += Indent + "/**\n";
237     code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
238     code += Indent + " */\n";
239     code += Indent + "public function get";
240     code += MakeCamel(field.name);
241     code += "()\n";
242     code += Indent + "{\n";
243     code += Indent + Indent + "$o = $this->__offset(" +
244             NumToString(field.value.offset) + ");\n" + Indent + Indent +
245             "return $o != 0 ? ";
246     code += "$this->bb->get";
247     code += MakeCamel(GenTypeGet(field.value.type)) + "($o + $this->bb_pos)";
248     code += " : " + GenDefaultValue(field.value) + ";\n";
249     code += Indent + "}\n\n";
250   }
251 
252   // Get a struct by initializing an existing struct.
253   // Specific to Struct.
GetStructFieldOfStruct(const FieldDef & field,std::string * code_ptr)254   void GetStructFieldOfStruct(const FieldDef &field, std::string *code_ptr) {
255     std::string &code = *code_ptr;
256 
257     code += Indent + "/**\n";
258     code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
259     code += Indent + " */\n";
260     code += Indent + "public function get";
261     code += MakeCamel(field.name) + "()\n";
262     code += Indent + "{\n";
263     code += Indent + Indent + "$obj = new ";
264     code += GenTypeGet(field.value.type) + "();\n";
265     code += Indent + Indent + "$obj->init($this->bb_pos + ";
266     code += NumToString(field.value.offset) + ", $this->bb);";
267     code += "\n" + Indent + Indent + "return $obj;\n";
268     code += Indent + "}\n\n";
269   }
270 
271   // Get a struct by initializing an existing struct.
272   // Specific to Table.
GetStructFieldOfTable(const FieldDef & field,std::string * code_ptr)273   void GetStructFieldOfTable(const FieldDef &field, std::string *code_ptr) {
274     std::string &code = *code_ptr;
275 
276     code += Indent + "public function get";
277     code += MakeCamel(field.name);
278     code += "()\n";
279     code += Indent + "{\n";
280     code += Indent + Indent + "$obj = new ";
281     code += MakeCamel(GenTypeGet(field.value.type)) + "();\n";
282     code += Indent + Indent + "$o = $this->__offset(" +
283             NumToString(field.value.offset) + ");\n";
284     code += Indent + Indent;
285     code += "return $o != 0 ? $obj->init(";
286     if (field.value.type.struct_def->fixed) {
287       code += "$o + $this->bb_pos, $this->bb) : ";
288     } else {
289       code += "$this->__indirect($o + $this->bb_pos), $this->bb) : ";
290     }
291     code += GenDefaultValue(field.value) + ";\n";
292     code += Indent + "}\n\n";
293   }
294 
295   // Get the value of a string.
GetStringField(const FieldDef & field,std::string * code_ptr)296   void GetStringField(const FieldDef &field, std::string *code_ptr) {
297     std::string &code = *code_ptr;
298     code += Indent + "public function get";
299     code += MakeCamel(field.name);
300     code += "()\n";
301     code += Indent + "{\n";
302     code += Indent + Indent + "$o = $this->__offset(" +
303             NumToString(field.value.offset) + ");\n";
304     code += Indent + Indent;
305     code += "return $o != 0 ? $this->__string($o + $this->bb_pos) : ";
306     code += GenDefaultValue(field.value) + ";\n";
307     code += Indent + "}\n\n";
308   }
309 
310   // Get the value of a union from an object.
GetUnionField(const FieldDef & field,std::string * code_ptr)311   void GetUnionField(const FieldDef &field, std::string *code_ptr) {
312     std::string &code = *code_ptr;
313 
314     code += Indent + "/**\n";
315     code += Indent + " * @return" + GenTypeBasic(field.value.type) + "\n";
316     code += Indent + " */\n";
317     code += Indent + "public function get";
318     code += MakeCamel(field.name) + "($obj)\n";
319     code += Indent + "{\n";
320     code += Indent + Indent + "$o = $this->__offset(" +
321             NumToString(field.value.offset) + ");\n";
322     code += Indent + Indent;
323     code += "return $o != 0 ? $this->__union($obj, $o) : null;\n";
324     code += Indent + "}\n\n";
325   }
326 
327   // Get the value of a vector's struct member.
GetMemberOfVectorOfStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)328   void GetMemberOfVectorOfStruct(const StructDef &struct_def,
329                                  const FieldDef &field, std::string *code_ptr) {
330     std::string &code = *code_ptr;
331     auto vectortype = field.value.type.VectorType();
332 
333     code += Indent + "/**\n";
334     code += Indent + " * @return" + GenTypeBasic(field.value.type) + "\n";
335     code += Indent + " */\n";
336     code += Indent + "public function get";
337     code += MakeCamel(field.name);
338     code += "($j)\n";
339     code += Indent + "{\n";
340     code += Indent + Indent + "$o = $this->__offset(" +
341             NumToString(field.value.offset) + ");\n";
342     code += Indent + Indent + "$obj = new ";
343     code += MakeCamel(GenTypeGet(field.value.type)) + "();\n";
344 
345     switch (field.value.type.base_type) {
346       case BASE_TYPE_STRUCT:
347         if (struct_def.fixed) {
348           code += Indent + Indent;
349           code += "return $o != 0 ? $obj->init($this->bb_pos +" +
350                   NumToString(field.value.offset) + ", $this->bb) : null;\n";
351         } else {
352           code += Indent + Indent + "return $o != 0 ? $obj->init(";
353           code += field.value.type.struct_def->fixed
354                       ? "$o + $this->bb_pos"
355                       : "$this->__indirect($o + $this->bb_pos)";
356           code += ", $this->bb) : null;\n";
357         }
358         break;
359       case BASE_TYPE_STRING:
360         code += "// base_type_string\n";
361         // TODO(chobie): do we need this?
362         break;
363       case BASE_TYPE_VECTOR:
364         if (vectortype.base_type == BASE_TYPE_STRUCT) {
365           code += Indent + Indent + "return $o != 0 ? $obj->init(";
366           if (vectortype.struct_def->fixed) {
367             code += "$this->__vector($o) + $j *";
368             code += NumToString(InlineSize(vectortype));
369           } else {
370             code += "$this->__indirect($this->__vector($o) + $j * ";
371             code += NumToString(InlineSize(vectortype)) + ")";
372           }
373           code += ", $this->bb) : null;\n";
374         }
375         break;
376       case BASE_TYPE_UNION:
377         code += Indent + Indent + "return $o != 0 ? $this->";
378         code += GenGetter(field.value.type) + "($obj, $o); null;\n";
379         break;
380       default: break;
381     }
382 
383     code += Indent + "}\n\n";
384   }
385 
386   // Get the value of a vector's non-struct member. Uses a named return
387   // argument to conveniently set the zero value for the result.
GetMemberOfVectorOfNonStruct(const FieldDef & field,std::string * code_ptr)388   void GetMemberOfVectorOfNonStruct(const FieldDef &field,
389                                     std::string *code_ptr) {
390     std::string &code = *code_ptr;
391     auto vectortype = field.value.type.VectorType();
392 
393     code += Indent + "/**\n";
394     code += Indent + " * @param int offset\n";
395     code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
396     code += Indent + " */\n";
397     code += Indent + "public function get";
398     code += MakeCamel(field.name);
399     code += "($j)\n";
400     code += Indent + "{\n";
401     code += Indent + Indent + "$o = $this->__offset(" +
402             NumToString(field.value.offset) + ");\n";
403 
404     if (field.value.type.VectorType().base_type == BASE_TYPE_STRING) {
405       code += Indent + Indent;
406       code += "return $o != 0 ? $this->__string($this->__vector($o) + $j * ";
407       code += NumToString(InlineSize(vectortype)) + ") : ";
408       code += GenDefaultValue(field.value) + ";\n";
409     } else {
410       code += Indent + Indent + "return $o != 0 ? $this->bb->get";
411       code += MakeCamel(GenTypeGet(field.value.type));
412       code += "($this->__vector($o) + $j * ";
413       code += NumToString(InlineSize(vectortype)) + ") : ";
414       code += GenDefaultValue(field.value) + ";\n";
415     }
416     code += Indent + "}\n\n";
417   }
418 
419   // Get the value of a vector's union member. Uses a named return
420   // argument to conveniently set the zero value for the result.
GetMemberOfVectorOfUnion(const FieldDef & field,std::string * code_ptr)421   void GetMemberOfVectorOfUnion(const FieldDef &field, std::string *code_ptr) {
422     std::string &code = *code_ptr;
423     auto vectortype = field.value.type.VectorType();
424 
425     code += Indent + "/**\n";
426     code += Indent + " * @param int offset\n";
427     code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
428     code += Indent + " */\n";
429     code += Indent + "public function get";
430     code += MakeCamel(field.name);
431     code += "($j, $obj)\n";
432     code += Indent + "{\n";
433     code += Indent + Indent + "$o = $this->__offset(" +
434             NumToString(field.value.offset) + ");\n";
435     code += Indent + Indent + "return $o != 0 ? ";
436     code += "$this->__union($obj, $this->__vector($o) + $j * ";
437     code += NumToString(InlineSize(vectortype)) + " - $this->bb_pos) : null;\n";
438     code += Indent + "}\n\n";
439   }
440 
441   // Recursively generate arguments for a constructor, to deal with nested
442   // structs.
StructBuilderArgs(const StructDef & struct_def,const char * nameprefix,std::string * code_ptr)443   static void StructBuilderArgs(const StructDef &struct_def,
444                                 const char *nameprefix, std::string *code_ptr) {
445     for (auto it = struct_def.fields.vec.begin();
446          it != struct_def.fields.vec.end(); ++it) {
447       auto &field = **it;
448       if (IsStruct(field.value.type)) {
449         // Generate arguments for a struct inside a struct. To ensure names
450         // don't clash, and to make it obvious
451         // these arguments are constructing
452         // a nested struct, prefix the name with the field name.
453         StructBuilderArgs(*field.value.type.struct_def,
454                           (nameprefix + (field.name + "_")).c_str(), code_ptr);
455       } else {
456         std::string &code = *code_ptr;
457         code += std::string(", $") + nameprefix;
458         code += MakeCamel(field.name, false);
459       }
460     }
461   }
462 
463   // Recursively generate struct construction statements and instert manual
464   // padding.
StructBuilderBody(const StructDef & struct_def,const char * nameprefix,std::string * code_ptr)465   static void StructBuilderBody(const StructDef &struct_def,
466                                 const char *nameprefix, std::string *code_ptr) {
467     std::string &code = *code_ptr;
468     code += Indent + Indent + "$builder->prep(";
469     code += NumToString(struct_def.minalign) + ", ";
470     code += NumToString(struct_def.bytesize) + ");\n";
471     for (auto it = struct_def.fields.vec.rbegin();
472          it != struct_def.fields.vec.rend(); ++it) {
473       auto &field = **it;
474       if (field.padding) {
475         code += Indent + Indent + "$builder->pad(";
476         code += NumToString(field.padding) + ");\n";
477       }
478       if (IsStruct(field.value.type)) {
479         StructBuilderBody(*field.value.type.struct_def,
480                           (nameprefix + (field.name + "_")).c_str(), code_ptr);
481       } else {
482         code += Indent + Indent + "$builder->put" + GenMethod(field) + "($";
483         code += nameprefix + MakeCamel(field.name, false) + ");\n";
484       }
485     }
486   }
487 
488   // Get the value of a table's starting offset.
GetStartOfTable(const StructDef & struct_def,std::string * code_ptr)489   static void GetStartOfTable(const StructDef &struct_def,
490                               std::string *code_ptr) {
491     std::string &code = *code_ptr;
492 
493     code += Indent + "/**\n";
494     code += Indent + " * @param FlatBufferBuilder $builder\n";
495     code += Indent + " * @return void\n";
496     code += Indent + " */\n";
497     code += Indent + "public static function start" + struct_def.name;
498     code += "(FlatBufferBuilder $builder)\n";
499     code += Indent + "{\n";
500     code += Indent + Indent + "$builder->StartObject(";
501     code += NumToString(struct_def.fields.vec.size());
502     code += ");\n";
503     code += Indent + "}\n\n";
504 
505     code += Indent + "/**\n";
506     code += Indent + " * @param FlatBufferBuilder $builder\n";
507     code += Indent + " * @return " + struct_def.name + "\n";
508     code += Indent + " */\n";
509     code += Indent + "public static function create" + struct_def.name;
510     code += "(FlatBufferBuilder $builder, ";
511 
512     for (auto it = struct_def.fields.vec.begin();
513          it != struct_def.fields.vec.end(); ++it) {
514       auto &field = **it;
515 
516       if (field.deprecated) continue;
517       code += "$" + field.name;
518       if (!(it == (--struct_def.fields.vec.end()))) { code += ", "; }
519     }
520     code += ")\n";
521     code += Indent + "{\n";
522     code += Indent + Indent + "$builder->startObject(";
523     code += NumToString(struct_def.fields.vec.size());
524     code += ");\n";
525     for (auto it = struct_def.fields.vec.begin();
526          it != struct_def.fields.vec.end(); ++it) {
527       auto &field = **it;
528       if (field.deprecated) continue;
529 
530       code += Indent + Indent + "self::add";
531       code += MakeCamel(field.name) + "($builder, $" + field.name + ");\n";
532     }
533 
534     code += Indent + Indent + "$o = $builder->endObject();\n";
535 
536     for (auto it = struct_def.fields.vec.begin();
537          it != struct_def.fields.vec.end(); ++it) {
538       auto &field = **it;
539       if (!field.deprecated && field.required) {
540         code += Indent + Indent + "$builder->required($o, ";
541         code += NumToString(field.value.offset);
542         code += ");  // " + field.name + "\n";
543       }
544     }
545     code += Indent + Indent + "return $o;\n";
546     code += Indent + "}\n\n";
547   }
548 
549   // Set the value of a table's field.
BuildFieldOfTable(const FieldDef & field,const size_t offset,std::string * code_ptr)550   static void BuildFieldOfTable(const FieldDef &field, const size_t offset,
551                                 std::string *code_ptr) {
552     std::string &code = *code_ptr;
553 
554     code += Indent + "/**\n";
555     code += Indent + " * @param FlatBufferBuilder $builder\n";
556     code += Indent + " * @param " + GenTypeBasic(field.value.type) + "\n";
557     code += Indent + " * @return void\n";
558     code += Indent + " */\n";
559     code += Indent + "public static function ";
560     code += "add" + MakeCamel(field.name);
561     code += "(FlatBufferBuilder $builder, ";
562     code += "$" + MakeCamel(field.name, false);
563     code += ")\n";
564     code += Indent + "{\n";
565     code += Indent + Indent + "$builder->add";
566     code += GenMethod(field) + "X(";
567     code += NumToString(offset) + ", ";
568 
569     code += "$" + MakeCamel(field.name, false);
570     code += ", ";
571 
572     if (field.value.type.base_type == BASE_TYPE_BOOL) {
573       code += "false";
574     } else {
575       code += field.value.constant;
576     }
577     code += ");\n";
578     code += Indent + "}\n\n";
579   }
580 
581   // Set the value of one of the members of a table's vector.
BuildVectorOfTable(const FieldDef & field,std::string * code_ptr)582   static void BuildVectorOfTable(const FieldDef &field, std::string *code_ptr) {
583     std::string &code = *code_ptr;
584 
585     auto vector_type = field.value.type.VectorType();
586     auto alignment = InlineAlignment(vector_type);
587     auto elem_size = InlineSize(vector_type);
588     code += Indent + "/**\n";
589     code += Indent + " * @param FlatBufferBuilder $builder\n";
590     code += Indent + " * @param array offset array\n";
591     code += Indent + " * @return int vector offset\n";
592     code += Indent + " */\n";
593     code += Indent + "public static function create";
594     code += MakeCamel(field.name);
595     code += "Vector(FlatBufferBuilder $builder, array $data)\n";
596     code += Indent + "{\n";
597     code += Indent + Indent + "$builder->startVector(";
598     code += NumToString(elem_size);
599     code += ", count($data), " + NumToString(alignment);
600     code += ");\n";
601     code += Indent + Indent;
602     code += "for ($i = count($data) - 1; $i >= 0; $i--) {\n";
603     if (IsScalar(field.value.type.VectorType().base_type)) {
604       code += Indent + Indent + Indent;
605       code += "$builder->put";
606       code += MakeCamel(GenTypeBasic(field.value.type.VectorType()));
607       code += "($data[$i]);\n";
608     } else {
609       code += Indent + Indent + Indent;
610       code += "$builder->putOffset($data[$i]);\n";
611     }
612     code += Indent + Indent + "}\n";
613     code += Indent + Indent + "return $builder->endVector();\n";
614     code += Indent + "}\n\n";
615 
616     code += Indent + "/**\n";
617     code += Indent + " * @param FlatBufferBuilder $builder\n";
618     code += Indent + " * @param int $numElems\n";
619     code += Indent + " * @return void\n";
620     code += Indent + " */\n";
621     code += Indent + "public static function start";
622     code += MakeCamel(field.name);
623     code += "Vector(FlatBufferBuilder $builder, $numElems)\n";
624     code += Indent + "{\n";
625     code += Indent + Indent + "$builder->startVector(";
626     code += NumToString(elem_size);
627     code += ", $numElems, " + NumToString(alignment);
628     code += ");\n";
629     code += Indent + "}\n\n";
630   }
631 
632   // Get the offset of the end of a table.
GetEndOffsetOnTable(const StructDef & struct_def,std::string * code_ptr)633   void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
634     std::string &code = *code_ptr;
635 
636     code += Indent + "/**\n";
637     code += Indent + " * @param FlatBufferBuilder $builder\n";
638     code += Indent + " * @return int table offset\n";
639     code += Indent + " */\n";
640     code += Indent + "public static function end" + struct_def.name;
641     code += "(FlatBufferBuilder $builder)\n";
642     code += Indent + "{\n";
643     code += Indent + Indent + "$o = $builder->endObject();\n";
644 
645     for (auto it = struct_def.fields.vec.begin();
646          it != struct_def.fields.vec.end(); ++it) {
647       auto &field = **it;
648       if (!field.deprecated && field.required) {
649         code += Indent + Indent + "$builder->required($o, ";
650         code += NumToString(field.value.offset);
651         code += ");  // " + field.name + "\n";
652       }
653     }
654     code += Indent + Indent + "return $o;\n";
655     code += Indent + "}\n";
656 
657     if (parser_.root_struct_def_ == &struct_def) {
658       code += "\n";
659       code += Indent + "public static function finish";
660       code += struct_def.name;
661       code += "Buffer(FlatBufferBuilder $builder, $offset)\n";
662       code += Indent + "{\n";
663       code += Indent + Indent + "$builder->finish($offset";
664 
665       if (parser_.file_identifier_.length())
666         code += ", \"" + parser_.file_identifier_ + "\"";
667       code += ");\n";
668       code += Indent + "}\n";
669     }
670   }
671 
672   // Generate a struct field, conditioned on its child type(s).
GenStructAccessor(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)673   void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
674                          std::string *code_ptr) {
675     GenComment(field.doc_comment, code_ptr, nullptr);
676 
677     if (IsScalar(field.value.type.base_type)) {
678       if (struct_def.fixed) {
679         GetScalarFieldOfStruct(field, code_ptr);
680       } else {
681         GetScalarFieldOfTable(field, code_ptr);
682       }
683     } else {
684       switch (field.value.type.base_type) {
685         case BASE_TYPE_STRUCT:
686           if (struct_def.fixed) {
687             GetStructFieldOfStruct(field, code_ptr);
688           } else {
689             GetStructFieldOfTable(field, code_ptr);
690           }
691           break;
692         case BASE_TYPE_STRING: GetStringField(field, code_ptr); break;
693         case BASE_TYPE_VECTOR: {
694           auto vectortype = field.value.type.VectorType();
695           if (vectortype.base_type == BASE_TYPE_UNION) {
696             GetMemberOfVectorOfUnion(field, code_ptr);
697           } else if (vectortype.base_type == BASE_TYPE_STRUCT) {
698             GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
699           } else {
700             GetMemberOfVectorOfNonStruct(field, code_ptr);
701           }
702           break;
703         }
704         case BASE_TYPE_UNION: GetUnionField(field, code_ptr); break;
705         default: FLATBUFFERS_ASSERT(0);
706       }
707     }
708     if (field.value.type.base_type == BASE_TYPE_VECTOR) {
709       GetVectorLen(field, code_ptr);
710       if (field.value.type.element == BASE_TYPE_UCHAR) {
711         GetUByte(field, code_ptr);
712       }
713     }
714   }
715 
716   // Generate table constructors, conditioned on its members' types.
GenTableBuilders(const StructDef & struct_def,std::string * code_ptr)717   void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
718     GetStartOfTable(struct_def, code_ptr);
719 
720     for (auto it = struct_def.fields.vec.begin();
721          it != struct_def.fields.vec.end(); ++it) {
722       auto &field = **it;
723       if (field.deprecated) continue;
724 
725       auto offset = it - struct_def.fields.vec.begin();
726       if (field.value.type.base_type == BASE_TYPE_UNION) {
727         std::string &code = *code_ptr;
728         code += Indent + "public static function add";
729         code += MakeCamel(field.name);
730         code += "(FlatBufferBuilder $builder, $offset)\n";
731         code += Indent + "{\n";
732         code += Indent + Indent + "$builder->addOffsetX(";
733         code += NumToString(offset) + ", $offset, 0);\n";
734         code += Indent + "}\n\n";
735       } else {
736         BuildFieldOfTable(field, offset, code_ptr);
737       }
738       if (field.value.type.base_type == BASE_TYPE_VECTOR) {
739         BuildVectorOfTable(field, code_ptr);
740       }
741     }
742 
743     GetEndOffsetOnTable(struct_def, code_ptr);
744   }
745 
746   // Generate struct or table methods.
GenStruct(const StructDef & struct_def,std::string * code_ptr)747   void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
748     if (struct_def.generated) return;
749 
750     GenComment(struct_def.doc_comment, code_ptr, nullptr);
751     BeginClass(struct_def, code_ptr);
752 
753     if (!struct_def.fixed) {
754       // Generate a special accessor for the table that has been declared as
755       // the root type.
756       NewRootTypeFromBuffer(struct_def, code_ptr);
757     }
758 
759     std::string &code = *code_ptr;
760     if (!struct_def.fixed) {
761       if (parser_.file_identifier_.length()) {
762         // Return the identifier
763         code += Indent + "public static function " + struct_def.name;
764         code += "Identifier()\n";
765         code += Indent + "{\n";
766         code += Indent + Indent + "return \"";
767         code += parser_.file_identifier_ + "\";\n";
768         code += Indent + "}\n\n";
769 
770         // Check if a buffer has the identifier.
771         code += Indent + "public static function " + struct_def.name;
772         code += "BufferHasIdentifier(ByteBuffer $buf)\n";
773         code += Indent + "{\n";
774         code += Indent + Indent + "return self::";
775         code += "__has_identifier($buf, self::";
776         code += struct_def.name + "Identifier());\n";
777         code += Indent + "}\n\n";
778       }
779 
780       if (parser_.file_extension_.length()) {
781         // Return the extension
782         code += Indent + "public static function " + struct_def.name;
783         code += "Extension()\n";
784         code += Indent + "{\n";
785         code += Indent + Indent + "return \"" + parser_.file_extension_;
786         code += "\";\n";
787         code += Indent + "}\n\n";
788       }
789     }
790 
791     // Generate the Init method that sets the field in a pre-existing
792     // accessor object. This is to allow object reuse.
793     InitializeExisting(struct_def, code_ptr);
794     for (auto it = struct_def.fields.vec.begin();
795          it != struct_def.fields.vec.end(); ++it) {
796       auto &field = **it;
797       if (field.deprecated) continue;
798 
799       GenStructAccessor(struct_def, field, code_ptr);
800     }
801 
802     if (struct_def.fixed) {
803       // create a struct constructor function
804       GenStructBuilder(struct_def, code_ptr);
805     } else {
806       // Create a set of functions that allow table construction.
807       GenTableBuilders(struct_def, code_ptr);
808     }
809     EndClass(code_ptr);
810   }
811 
812   // Generate enum declarations.
GenEnum(const EnumDef & enum_def,std::string * code_ptr)813   static void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
814     if (enum_def.generated) return;
815 
816     GenComment(enum_def.doc_comment, code_ptr, nullptr);
817     BeginEnum(enum_def.name, code_ptr);
818     for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
819          ++it) {
820       auto &ev = **it;
821       GenComment(ev.doc_comment, code_ptr, nullptr);
822       EnumMember(ev, code_ptr);
823     }
824 
825     std::string &code = *code_ptr;
826     code += "\n";
827     code += Indent + "private static $names = array(\n";
828     for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
829          ++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