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