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