0Pricing
PHP Academy · Lektion

Ein Schema mit graphql-php erstellen

Typen und ein Schema mit webonyx/graphql-php definieren

Ein Schema mit graphql-php erstellen ist eine kostenlose PHP Academy-Lektion auf CoddyKit. Dies ist Lektion 2 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des PHP Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der PHP Academy-Kurs umfasst insgesamt 4 Lektionen.

graphql-php: Die Referenzimplementierung

webonyx/graphql-php ist die De-facto-PHP-Portierung der GraphQL-Referenzimplementierung. Sie liefert Ihnen Typsystem, Parser, Validator und Executor. Sie definieren Ihr Schema entweder programmatisch (PHP-Objekte) oder aus SDL (schema-first). In dieser Lektion erstellen wir ein Schema von Hand, damit Sie genau verstehen, was die einzelnen Bestandteile tun.

composer require webonyx/graphql-php

Skalare und die Typ-Registry

Jeder GraphQL-Wert läuft letztlich auf einen Skalar hinaus: Int, Float, String, Boolean, ID. In graphql-php liegen diese auf der Type-Fassade. Da Objekttypen aufeinander (und auf sich selbst) verweisen, ist eine statische TypeRegistry ein gängiges Muster, die jeden Typ zwischenspeichert, sodass Sie ihn nur einmal erstellen.

<?php
use GraphQL\Type\Definition\Type;

// Built-in scalars, returned as singletons:
var_dump(Type::int()->name);     // "Int"
var_dump(Type::string()->name);  // "String"
var_dump(Type::id()->name);      // "ID"
var_dump(Type::nonNull(Type::string())->toString()); // "String!"

Einen ObjectType definieren

Ein ObjectType hat einen name und eine fields-Map. Jedes Feld legt seinen type fest und kann optional einen resolve-Callback deklarieren. Wenn Sie resolve weglassen, verwendet graphql-php den Standard-Resolver, der den passenden Array-Schlüssel oder die Eigenschaft bzw. den Getter aus dem Parent-Wert liest.

<?php
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;

$postType = new ObjectType([
    'name' => 'Post',
    'fields' => [
        'id'    => Type::nonNull(Type::id()),
        'title' => Type::nonNull(Type::string()),
        'body'  => Type::string(),
    ],
]);

Non-Null- und Listen-Typen

Wrapping-Typen drücken Nullbarkeit und Kardinalität aus:

  • Type::nonNull(T) → T! (nie null).
  • Type::listOf(T) → [T] (eine Liste, möglicherweise null und möglicherweise mit null-Elementen).
  • [Post!]! = eine Non-Null-Liste aus Non-Null-Posts → nonNull(listOf(nonNull($postType))).

Behalten Sie dies im Hinterkopf: Es ist der Nullbarkeitsvertrag Ihres Schemas mit den Clients.

<?php
use GraphQL\Type\Definition\Type;

// [Post!]!  -- a required list whose elements are never null
$wrapped = Type::nonNull(Type::listOf(Type::nonNull(Type::string())));
echo $wrapped->toString(), "\n"; // [String!]!

Lazy Fields durchbrechen zirkuläre Referenzen

Ein User hat posts, und ein Post hat einen author (einen User). Um Typen aufzubauen, die gegenseitig aufeinander verweisen, übergeben Sie fields als Closure statt als Array. Die Closure wird verzögert ausgeführt, nachdem beide Typen existieren, und umgeht so das Henne-Ei-Problem.

<?php
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;

class Types {
    private static array $cache = [];

    public static function user(): ObjectType {
        return self::$cache['User'] ??= new ObjectType([
            'name' => 'User',
            'fields' => fn() => [           // lazy!
                'id'    => Type::nonNull(Type::id()),
                'name'  => Type::nonNull(Type::string()),
                'posts' => Type::listOf(self::post()),
            ],
        ]);
    }

    public static function post(): ObjectType {
        return self::$cache['Post'] ??= new ObjectType([
            'name' => 'Post',
            'fields' => fn() => [
                'id'     => Type::nonNull(Type::id()),
                'title'  => Type::nonNull(Type::string()),
                'author' => self::user(),    // back-reference
            ],
        ]);
    }
}

Feldargumente

Felder können Argumente entgegennehmen. Deklarieren Sie sie unter dem Schlüssel args; sie treffen als zweiter Parameter ($args) des Resolvers ein. Argumente sind selbst typisiert, können Non-Null sein und defaultValue enthalten.

<?php
use GraphQL\Type\Definition\Type;

$userField = [
    'type' => Type::string(),
    'args' => [
        'id'     => Type::nonNull(Type::id()),
        'locale' => ['type' => Type::string(), 'defaultValue' => 'en'],
    ],
    'resolve' => fn($root, array $args) => "user {$args['id']} ({$args['locale']})",
];

Der Root-Query-Typ

Jedes Schema benötigt einen Root-Typ Query — die Einstiegspunkte, an denen Clients ihre Abfragen beginnen können. Hier stellen wir ein einzelnes hello-Feld bereit, damit wir die Ausführung durchgängig testen können. Das erste Argument des Root-Resolvers ist der rootValue des Schemas (häufig null).

<?php
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;

$queryType = new ObjectType([
    'name' => 'Query',
    'fields' => [
        'hello' => [
            'type' => Type::string(),
            'args' => ['name' => Type::nonNull(Type::string())],
            'resolve' => fn($root, array $args) => 'Hello, ' . $args['name'],
        ],
    ],
]);

Schema zusammenbauen und ausführen

Verpacken Sie den Query-Typ in ein Schema und führen Sie einen Query-String über GraphQL::executeQuery() aus. Das Ergebnisobjekt wird über toArray() in das kanonische Array { data, errors } umgewandelt.

<?php
require 'vendor/autoload.php';

use GraphQL\GraphQL;
use GraphQL\Type\Schema;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;

$queryType = new ObjectType([
    'name' => 'Query',
    'fields' => [
        'hello' => [
            'type' => Type::string(),
            'args' => ['name' => Type::nonNull(Type::string())],
            'resolve' => fn($root, $args) => 'Hello, ' . $args['name'],
        ],
    ],
]);

$schema = new Schema(['query' => $queryType]);
$result = GraphQL::executeQuery($schema, '{ hello(name: "Ada") }');
echo json_encode($result->toArray());
// {"data":{"hello":"Hello, Ada"}}

Schema-first-Alternative mit BuildSchema

Wenn Sie SDL bevorzugen, analysiert BuildSchema::build() einen Schema-String und erstellt daraus ein ausführbares Schema. Anschließend binden Sie Resolver separat an (z. B. über einen Field-Resolver-Callback). So bleiben die Typdefinitionen deklarativ, während die Logik in PHP verbleibt.

<?php
use GraphQL\Utils\BuildSchema;

$sdl = <<<'GQL'
type Query {
  hello(name: String!): String
}
GQL;

$schema = BuildSchema::build($sdl);
// Provide resolvers via the executeQuery $fieldResolver argument
// or with a type config decorator.

Vor dem Deployment validieren

graphql-php validiert eingehende Abfragen vor der Ausführung automatisch anhand des Schemas. Sie können außerdem zur Build-/CI-Zeit mit $schema->assertValid() prüfen, dass das Schema selbst intern konsistent ist — so erkennen Sie Tippfehler und fehlerhafte Verweise vor dem Deployment und nicht erst zum Zeitpunkt der Anfrage.

<?php
use GraphQL\Type\Schema;

/** @var Schema $schema */
$schema->assertValid(); // throws InvariantViolation on a broken schema
echo "schema OK\n";

Enums und benutzerdefinierte Skalare

Neben Objekten ergänzen zwei weitere Typarten die meisten Schemas. EnumType beschränkt ein Feld auf eine feste Menge benannter Werte. Mit CustomScalarType können Sie Domänen-Skalare (DateTime, Email) mit eigener serialize/parseValue/parseLiteral-Logik definieren, sodass Werte an der Grenze validiert und normalisiert werden.

<?php
use GraphQL\Type\Definition\EnumType;

$statusEnum = new EnumType([
    'name' => 'PostStatus',
    'values' => [
        'DRAFT'     => ['value' => 0],
        'PUBLISHED' => ['value' => 1],
        'ARCHIVED'  => ['value' => 2],
    ],
]);
// A field typed as $statusEnum only accepts DRAFT/PUBLISHED/ARCHIVED.

Wissenscheck

Warum übergeben Sie fields als Closure?

Zusammenfassung

Sie haben ein Schema von Grund auf aufgebaut:

  • Skalare und Wrapping-Typen (nonNull, listOf) drücken den Vertrag für Nullbarkeit und Kardinalität aus.
  • ObjectType mit einer Fields-Map (oder Lazy-Closure) definiert Ihre Strukturen.
  • Eine zwischenspeichernde Typ-Registry verarbeitet zirkuläre Referenzen.
  • Felder akzeptieren typisierte args; der Root-Typ Query ist der Einstiegspunkt.
  • GraphQL::executeQuery() führt es aus; assertValid() schützt das Schema in der CI.

Als Nächstes: Resolver, Mutations und Subscriptions.

Häufig gestellte Fragen

Ist die Lektion „Ein Schema mit graphql-php erstellen“ kostenlos?

Ja — der vollständige Text von „Ein Schema mit graphql-php erstellen“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des PHP Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der PHP Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Ein Schema mit graphql-php erstellen“?

Typen und ein Schema mit webonyx/graphql-php definieren Du übst PHP Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um PHP Academy zu starten?

Keine Vorkenntnisse erforderlich. PHP Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 2 von 4.

Wie lange dauert die Lektion „Ein Schema mit graphql-php erstellen“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser PHP Academy-Lektion Code schreiben und ausführen?

Ja. Jede PHP Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. GraphQL vs. REST
  2. Ein Schema mit graphql-php erstellen
  3. Resolver, Mutationen und Subscriptions
  4. Performance: N+1 und DataLoader
← Zurück zu PHP Academy