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