Skip to content Documentation index for agents (llms.txt)
Glotto Beta
Get started

PHP

The PHP SDK is an idiomatic, Composer-installable client emitted from the same GlottoIR as every other target. Files declare strict_types=1, models are typed-property objects with fromJson, and PHPDoc is generated from the operation prose in the spec.

Manual pages expose typed items, the full response and explicit continuation. A trailing RequestOptions controls headers, deadlines, retries, extra parameters and cooperative cancellation. Binary operations return an owned Core\BinaryDownload with bounded readAll, pipe, response metadata and close; foreach closes on break or error. See pagination, request retries and controls, streaming, and file transfers.

Quickstart

composer require your-org/petstore
<?php
require 'vendor/autoload.php';

$client = new Petstore\Client(token: '<token>');
$result = $client->pets->get('...');
var_dump($result);

Resource objects

Operations are camelCase methods on resource objects — $client->pets->get($id), $client->pets->photos->add(...) — the Stripe-PHP service-accessor shape, rather than flat snake_case methods.

PSR-18 transport

The client sends requests through an injectable PSR-18 HTTP client (Guzzle by default), so the transport is swappable and mockable — the PHP-ecosystem standard, the analogue of C#’s injectable HttpClient.

Typed errors

Non-2xx responses throw ApiError, an \Exception hierarchy carrying the parsed, typed error body; discriminated-union response bodies resolve to the right concrete type. See Errors.

Pagination

List methods return a lazy iterator (foreach) that walks every page, advancing the cursor for you. See Pagination.

Retries & backoff

Transient failures (5xx, 429, transport errors) retry with exponential backoff and jitter, configurable per client. See Retries & timeouts, Streaming, and Authentication.

Unknown response fields

Your API can add a response field without it being a breaking change — but a generated class has no promoted property to put it in, and its fromJson factory reads only the fields it declares. The generated models keep it instead: a field the SDK wasn’t generated from is retained on decode, readable through an accessor, and written back out when the model is re-serialized.

$pet = $client->pets->createPet($body);

// A field your API started returning after this SDK was generated.
$species = $pet->extraFields()['species'] ?? null;

// Re-encoding preserves it — a read-modify-write never silently drops it.
$json = json_encode($pet);

extraFields() returns an array<string, mixed>, so nested objects and lists survive intact, and retention is recursive.

One caveat from PHP’s JSON decoder: json_decode($body, true) represents an empty JSON object and an empty array identically, so an unknown field whose value is {} round-trips as []. Every other shape — nested objects, lists, scalars, null — round-trips unchanged.

Your existing construction still compiles: the storage is a private field assigned after construction, so the promoted constructor is untouched.

The retained fields are read-only by design. To send a field your spec doesn’t model yet, use the per-call extra-body escape hatch rather than writing to the retained bag.

Missing and null fields

By default an optional property that decodes from JSON null is null, the same as an omitted key, and jsonSerialize() drops it — so a read-modify-write sends a decoded null back as an absent key. Set targets.php.model_presence: explicit to keep missing, null and a value apart: optional arguments default to the ModelFieldMissing::Value singleton, null means JSON null, and a generated copy method sets or removes fields. That changes property and constructor types; the generated README shows the idioms.