Создание схемы с graphql-php
Определяйте типы и схему с помощью webonyx/graphql-php
«Создание схемы с graphql-php» — бесплатный урок PHP Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения PHP Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс PHP Academy содержит 4 уроков всего.
graphql-php: эталонная реализация
webonyx/graphql-php — фактический перенос эталонной реализации GraphQL на PHP. Он предоставляет систему типов, синтаксический анализатор, проверку и исполнитель. Вы определяете схему либо программно (объектами PHP), либо из SDL (сначала схема). В этом уроке мы создадим схему вручную, чтобы Вы точно понимали назначение каждой её части.
composer require webonyx/graphql-phpСкалярные типы и реестр типов
В конечном счёте каждое значение GraphQL является скалярным типом: Int, Float, String, Boolean, ID. В graphql-php они находятся в фасаде Type. Поскольку типы объектов ссылаются друг на друга и на самих себя, часто используют статический TypeRegistry, который кэширует каждый тип, чтобы создавать его только один раз.
<?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!"
Определение ObjectType
У ObjectType есть name и карта fields. Каждое поле объявляет свой type и, при необходимости, обратный вызов resolve. Если не указывать resolve, graphql-php использует резолвер по умолчанию: он читает соответствующий ключ массива, свойство или метод доступа родительского значения.
<?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(),
],
]);
Обёртки для ненулевых значений и списков
Типы-обёртки выражают допустимость отсутствующих значений и количество элементов:
Type::nonNull(T)→T!(значение никогда не отсутствует).Type::listOf(T)→[T](список, который может отсутствовать и может содержать отсутствующие элементы).[Post!]!= список, который сам не может отсутствовать и содержит только существующие публикации →nonNull(listOf(nonNull($postType))).
Важно сделать это правильно: так задаётся контракт схемы для клиентов относительно отсутствующих значений.
<?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!]!
Ленивые поля устраняют циклические ссылки
У User есть posts, а у Post есть author (пользователь User). Чтобы создать взаимно ссылающиеся типы, передайте fields как замыкание, а не как массив. Замыкание выполняется после создания обоих типов, что позволяет решить проблему курицы и яйца.
<?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
],
]);
}
}
Аргументы полей
Поля могут принимать аргументы. Объявляйте их под ключом args; они передаются вторым параметром ($args) резолвера. Аргументы сами имеют типы, могут быть обязательными и могут содержать defaultValue.
<?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']})",
];
Корневой тип Query
Каждой схеме нужен корневой тип Query — точки входа, с которых клиенты начинают запросы. Здесь мы предоставляем единственное поле hello, чтобы выполнить запрос от начала до конца. Первый аргумент корневого резолвера — это rootValue схемы (часто 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 и передайте строку запроса в GraphQL::executeQuery(). Объект результата преобразуется в канонический массив { data, errors } с помощью toArray().
<?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"}}
Альтернатива с подходом «сначала схема» и BuildSchema
Если Вы предпочитаете SDL, BuildSchema::build() разбирает строку схемы и создаёт исполняемую схему. Затем Вы отдельно подключаете резолверы (например, обратный вызов для обработки поля), сохраняя декларативными определения типов, а логику — в PHP.
<?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.
Проверяйте перед выпуском
graphql-php автоматически проверяет входящие запросы по схеме перед выполнением. Вы также можете проверить внутреннюю согласованность самой схемы во время сборки или в CI с помощью $schema->assertValid() — обнаружить опечатки и недействительные ссылки лучше до развёртывания, а не во время обработки запроса.
<?php
use GraphQL\Type\Schema;
/** @var Schema $schema */
$schema->assertValid(); // throws InvariantViolation on a broken schema
echo "schema OK\n";
Перечисления и пользовательские скалярные типы
Помимо объектов, большинство схем дополняют ещё два вида типов. EnumType ограничивает поле фиксированным набором именованных значений. CustomScalarType позволяет определить предметные скалярные типы (DateTime, электронная почта) с собственной логикой serialize/parseValue/parseLiteral, чтобы значения проверялись и нормализовались на границе системы.
<?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.
Быстрая проверка
Зачем передавать fields как замыкание?
Повторение
Вы создали схему с нуля:
- Скалярные типы и типы-обёртки (
nonNull,listOf) задают контракт для отсутствующих значений и количества элементов. ObjectTypeс картой полей или ленивым замыканием определяет структуру данных.- Кэширующий реестр типов обрабатывает циклические ссылки.
- Поля принимают типизированные
args; корневой типQueryявляется точкой входа. GraphQL::executeQuery()выполняет запрос;assertValid()защищает схему в CI.
Далее: резолверы, мутации и подписки.
Изучай PHP с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 49
- Уроки
- 195
Часто задаваемые вопросы
Урок «Создание схемы с graphql-php» бесплатный?
Да — полный текст урока «Создание схемы с graphql-php» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс PHP Academy, подпишись на CoddyKit PRO. Курс PHP Academy содержит 4 уроков всего.
Чему я научусь в уроке «Создание схемы с graphql-php»?
Определяйте типы и схему с помощью webonyx/graphql-php Ты практикуешь PHP Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать PHP Academy?
Предыдущий опыт не требуется. PHP Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Создание схемы с graphql-php»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке PHP Academy?
Да. Каждый урок PHP Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- GraphQL и REST
- Создание схемы с graphql-php
- Резолверы, мутации и подписки
- Производительность: N+1 и DataLoader