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