PHP Generierter Code-Leitfaden
Sie sollten den proto3 Sprachleitfaden oder den Editions Sprachleitfaden lesen, bevor Sie dieses Dokument lesen. Beachten Sie, dass der Protocol Buffer Compiler derzeit nur Code-Generierung für proto3 und Editionen für PHP unterstützt.
Compiler-Aufruf
Der Protocol Buffer Compiler erzeugt PHP-Ausgabe, wenn er mit dem Kommandozeilenflag --php_out= aufgerufen wird. Der Parameter für die Option --php_out= ist das Verzeichnis, in dem der Compiler Ihre PHP-Ausgabe schreiben soll. Um PSR-4 zu entsprechen, erstellt der Compiler ein Unterverzeichnis, das dem im Proto-File definierten Paket entspricht. Zusätzlich wird für jede Nachricht im Proto-File-Input eine separate Datei im Unterverzeichnis des Pakets erstellt. Die Namen der Ausgabedateien von Nachrichten setzen sich aus drei Teilen zusammen
- Basisverzeichnis: Der Proto-Pfad (angegeben mit dem Kommandozeilenflag
--proto_path=oder-I) wird durch den Ausgabepfad (angegeben mit dem Flag--php_out=) ersetzt. - Unterverzeichnis:
.im Paketnamen werden durch den Verzeichnistrennzeichen des Betriebssystems ersetzt. Jede Komponente des Paketnamens wird großgeschrieben. - Datei: Der Nachrichtenname wird um
.phpergänzt.
Nehmen wir also zum Beispiel an, Sie rufen den Compiler wie folgt auf:
protoc --proto_path=src --php_out=build/gen src/example.proto
Und src/example.proto ist definiert als
edition = "2023";
package foo.bar;
message MyMessage {}
Der Compiler liest die Datei src/foo.proto und erzeugt die Ausgabedatei: build/gen/Foo/Bar/MyMessage.php. Der Compiler erstellt das Verzeichnis build/gen/Foo/Bar automatisch, falls erforderlich, aber er erstellt nicht build oder build/gen; diese müssen bereits existieren.
Pakete (Packages)
Der im .proto-File definierte Paketname wird standardmäßig verwendet, um eine Modulstruktur für die generierten PHP-Klassen zu erstellen. Angenommen, eine Datei wie
package foo.bar;
message MyMessage {}
Der Protokollcompiler generiert eine Ausgabeklasse mit dem Namen Foo\Bar\MyMessage.
Namespace-Optionen
Der Compiler unterstützt zusätzliche Optionen zur Definition des PHP- und Metadaten-Namespaces. Wenn diese definiert sind, werden sie zur Generierung der Modulstruktur und des Namespaces verwendet. Angenommen, Optionen wie
package foo.bar;
option php_namespace = "baz\\qux";
option php_metadata_namespace = "Foo";
message MyMessage {}
Der Protokollcompiler generiert eine Ausgabeklasse mit dem Namen baz\qux\MyMessage. Die Klasse erhält den Namespace namespace baz\qux.
Der Protokollcompiler generiert eine Metadatenklasse mit dem Namen Foo\Metadata. Die Klasse erhält den Namespace namespace Foo.
Die generierten Optionen sind case-sensitiv. Standardmäßig wird das Paket in PascalCase konvertiert.
Nachrichten
Angesichts einer einfachen Nachrichten Deklaration:
message Foo {
int32 int32_value = 1;
string string_value = 2;
repeated int32 repeated_int32_value = 3;
map<int32, int32> map_int32_int32_value = 4;
}
Der Protocol Buffer Compiler generiert eine PHP-Klasse namens Foo. Diese Klasse erbt von einer gemeinsamen Basisklasse, Google\Protobuf\Internal\Message, die Methoden zum Kodieren und Dekodieren Ihrer Nachrichtentypen bereitstellt, wie im folgenden Beispiel gezeigt
$from = new Foo();
$from->setInt32Value(1);
$from->setStringValue('a');
$from->getRepeatedInt32Value()[] = 1;
$from->getMapInt32Int32Value()[1] = 1;
$data = $from->serializeToString();
$to = new Foo();
try {
$to->mergeFromString($data);
} catch (Exception $e) {
// Handle parsing error from invalid data.
...
}
Sie sollten keine eigenen Foo-Unterklassen erstellen. Generierte Klassen sind nicht für die Unterklasse gedacht und können zu Problemen mit "fragilen Basisklassen" führen.
Verschachtelte Nachrichten führen zu einer PHP-Klasse mit demselben Namen, der mit ihrer enthaltenden Nachricht präfixiert und durch Unterstriche getrennt ist, da PHP keine verschachtelten Klassen unterstützt. Wenn Sie also beispielsweise Folgendes in Ihrer .proto-Datei haben
message TestMessage {
message NestedMessage {
int32 a = 1;
}
}
Der Compiler generiert die folgende Klasse
// PHP doesn’t support nested classes.
class TestMessage_NestedMessage {
public function __construct($data = NULL) {...}
public function getA() {...}
public function setA($var) {...}
}
Wenn der Nachrichtenklassenname reserviert ist (z. B. Empty), wird das Präfix PB vor den Klassennamen gestellt
class PBEmpty {...}
Wir haben auch die Datei-Level-Option php_class_prefix bereitgestellt. Wenn diese angegeben ist, wird sie allen generierten Nachrichtenkassen vorangestellt.
Felder
Für jedes Feld in einem Nachrichtentyp generiert der Protocol Buffer Compiler eine Reihe von Zugriffsermethoden, um das Feld zu setzen und abzurufen. Die Zugriffsermethoden werden mit snake_case-Feldnamen benannt, die in PascalCase konvertiert werden. Für ein Feld field_name sind die Zugriffsermethoden also getFieldName und setFieldName.
// optional MyEnum optional_enum
$m->getOptionalEnum();
$m->setOptionalEnum(MyEnum->FOO);
$m->hasOptionalEnum();
$m->clearOptionalEnum();
// MyEnum implicit_enum
$m->getImplicitEnum();
$m->setImplicitEnum(MyEnum->FOO);
Immer wenn Sie ein Feld setzen, wird der Wert gegen den deklarierten Typ dieses Feldes auf Typkompatibilität geprüft. Wenn der Wert vom falschen Typ ist (oder außerhalb des Bereichs liegt), wird eine Ausnahme ausgelöst. Standardmäßig sind Typkonvertierungen (z. B. beim Zuweisen eines Wertes zu einem Feld oder beim Hinzufügen eines Elements zu einem wiederholten Feld) von und zu Ganzzahlen, Gleitkommazahlen und numerischen Zeichenketten zulässig. Nicht zulässige Konvertierungen umfassen alle Konvertierungen von/zu Arrays oder Objekten. Überläufe von Gleitkommazahlen zu Ganzzahlen sind undefiniert.
Die entsprechenden PHP-Typen für jeden Skalar-Protokollpuffertyp finden Sie in der Tabelle der Skalar-Werttypen.
has... und clear...
Für Felder mit expliziter Anwesenheit generiert der Compiler eine has...()-Methode. Diese Methode gibt true zurück, wenn das Feld gesetzt ist.
Der Compiler generiert auch eine clear...()-Methode. Diese Methode löscht das Feld. Nach dem Aufruf dieser Methode gibt has...() false zurück.
Für Felder mit impliziter Anwesenheit generiert der Compiler keine has...()- oder clear...()-Methoden. Für diese Felder können Sie die Anwesenheit prüfen, indem Sie den Feldwert mit dem Standardwert vergleichen.
Singuläre Nachrichtenfelder
Für ein Feld mit einem Nachrichtentyp generiert der Compiler dieselben Zugriffsermethoden wie für Skalartypen.
Ein Feld mit einem Nachrichtentyp hat standardmäßig den Wert null und wird beim Zugriff auf das Feld nicht automatisch erstellt. Sie müssen also Unternachrichten explizit erstellen, wie im Folgenden gezeigt
$m = new MyMessage();
$m->setZ(new SubMessage());
$m->getZ()->setFoo(42);
$m2 = new MyMessage();
$m2->getZ()->setFoo(42); // FAILS with an exception
Sie können jeder Instanz einem Nachrichtenfeld zuweisen, auch wenn die Instanz woanders gehalten wird (z. B. als Feldwert einer anderen Nachricht).
Wiederholte Felder
Der Protocol Buffer Compiler generiert ein spezielles RepeatedField für jedes wiederholte Feld. Wenn Sie also beispielsweise das folgende Feld haben
repeated int32 foo = 1;
Der generierte Code ermöglicht Ihnen Folgendes
$m->getFoo()[] =1;
$m->setFoo($array);
Map-Felder
Der Protocol Buffer Compiler generiert ein MapField für jedes Map-Feld. Bei diesem Feld
map<int32, int32> weight = 1;
Mit dem generierten Code können Sie Folgendes tun
$m->getWeight()[1] = 1;
Aufzählungen (Enums)
Da PHP keine nativen Enums hat, generiert der Protocol Buffer Compiler stattdessen eine PHP-Klasse für jeden Enum-Typ in Ihrer .proto-Datei, genau wie für Nachrichten, mit Konstanten für jeden Wert. Wenn Sie also diesen Enum haben
enum TestEnum {
Default = 0;
A = 1;
}
Der Compiler generiert die folgende Klasse
class TestEnum {
const DEFAULT = 0;
const A = 1;
}
Wie bei Nachrichten führt ein verschachtelter Enum zu einer PHP-Klasse mit demselben Namen, die mit seinen enthaltenden Nachricht(en) präfixiert und mit Unterstrichen getrennt ist, da PHP keine verschachtelten Klassen unterstützt.
class TestMessage_NestedEnum {...}
Wenn ein Enum-Klassen- oder Wertname reserviert ist (z. B. Empty), wird das Präfix PB dem Klassen- oder Wertnamen vorangestellt
class PBEmpty {
const PBECHO = 0;
}
Wir haben auch die Datei-Level-Option php_class_prefix bereitgestellt. Wenn diese angegeben ist, wird sie allen generierten Enum-Klassen vorangestellt.
Oneof
Für ein oneof generiert der Protocol Buffer Compiler eine has- und eine clear-Methode für jedes Feld im oneof, sowie eine spezielle Zugriffsermethode, die es Ihnen ermöglicht festzustellen, welches oneof-Feld (falls vorhanden) gesetzt ist. Angenommen Sie haben diese Nachricht
message TestMessage {
oneof test_oneof {
int32 oneof_int32 = 1;
int64 oneof_int64 = 2;
}
}
Der Compiler generiert die folgenden Felder und die spezielle Methode
class TestMessage {
private oneof_int32;
private oneof_int64;
public function getOneofInt32();
public function setOneofInt32($var);
public function getOneofInt64();
public function setOneofInt64($var);
public function getTestOneof(); // Return field name
}
Der Name der Zugriffsermethode basiert auf dem Namen des oneof und gibt eine Zeichenkette zurück, die das im oneof aktuell gesetzte Feld repräsentiert. Wenn das oneof nicht gesetzt ist, gibt die Methode eine leere Zeichenkette zurück.
Wenn Sie ein Feld in einem oneof setzen, werden automatisch alle anderen Felder im oneof gelöscht. Wenn Sie mehrere Felder in einem oneof setzen möchten, müssen Sie dies in separaten Anweisungen tun.
$m = new TestMessage();
$m->setOneofInt32(42); // $m->hasOneofInt32() is true
$m->setOneofInt64(123); // $m->hasOneofInt32() is now false