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