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