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