PHPackages                             zeusi/json-schema-extractor - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Validation &amp; Sanitization](/categories/validation)
4. /
5. zeusi/json-schema-extractor

ActiveLibrary[Validation &amp; Sanitization](/categories/validation)

zeusi/json-schema-extractor
===========================

Modular JSON Schema generator for PHP DTOs, extracting native types, PHPDoc, validation constraints, and serialization metadata

1.2.0(2w ago)02↓100%MITPHPPHP &gt;=8.1CI passing

Since May 21Pushed 2w agoCompare

[ Source](https://github.com/antonioturdo/json-schema-extractor)[ Packagist](https://packagist.org/packages/zeusi/json-schema-extractor)[ RSS](/packages/zeusi-json-schema-extractor/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (3)Dependencies (17)Versions (4)Used By (0)

JSON Schema Extractor
=====================

[](#json-schema-extractor)

[![Packagist Version](https://camo.githubusercontent.com/968ffe9d4bb73a679c2fead51258771f1fe55b9167b1ebb5220544036e9070a8/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7a657573692f6a736f6e2d736368656d612d657874726163746f722e737667)](https://packagist.org/packages/zeusi/json-schema-extractor)[![PHP](https://camo.githubusercontent.com/7af7d4dfef5d061a6b3cbf5834f0e449e6cef793f26372034dbc815ae3f3de73/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253345253344382e312d3737376262342e737667)](https://www.php.net/)[![CI](https://github.com/antonioturdo/json-schema-extractor/actions/workflows/ci.yml/badge.svg)](https://github.com/antonioturdo/json-schema-extractor/actions/workflows/ci.yml)[![PHPStan](https://camo.githubusercontent.com/6e33b77b51a771e6655e2b9229dca1682109fdbaae399ff6b2d6d7a4d5e35db7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068707374616e2d6c6576656c253230382d627269676874677265656e2e737667)](https://phpstan.org/)[![Coverage](https://camo.githubusercontent.com/d0fb702e0e60b2166e191d0df8d4c72d6459e26513163acbd92ee8ad413285aa/68747470733a2f2f636f6465636f762e696f2f67682f616e746f6e696f747572646f2f6a736f6e2d736368656d612d657874726163746f722f67726170682f62616467652e737667)](https://codecov.io/gh/antonioturdo/json-schema-extractor)[![License](https://camo.githubusercontent.com/f158269d165a1f9a544e8657a23471cbe3ed0a2337e45528172dcf78d8dba6fe/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f7a657573692f6a736f6e2d736368656d612d657874726163746f722e737667)](LICENSE)

> JSON Schema Extractor generates JSON Schema documents from PHP DTOs by extracting native types, PHPDoc, validation constraints, and serialization metadata through a modular pipeline.

Typical use cases include:

- structured output definitions for LLMs
- reusable DTO schemas for a broader AsyncAPI documentation flow

Features
--------

[](#features)

- **No mandatory dependencies**: install only the optional packages needed by the components you enable.
- **Existing metadata first**: builds schemas from native PHP types, PHPDoc, Symfony Validator, and serializer metadata without requiring schema-specific attributes.
- **PHPDoc-aware enrichment**: reads PHPDoc through the PHPStan or phpDocumentor based enrichers, covering generics, shaped arrays, literals, ranges, enums, nullable types, and text metadata.
- **Symfony integration**: maps supported Symfony Validator constraints and projects output shapes through Symfony Serializer metadata such as groups, serialized names, name converters, discriminators, and known normalizers.
- **Reference-safe object graphs**: handles nested DTOs, reusable definitions, enums, and circular references through `$ref`.
- **Serialization-aware output**: separates the PHP model from the JSON-facing shape, with built-in strategies for PHP `json_encode()` and Symfony Serializer.

Installation
------------

[](#installation)

```
composer require zeusi/json-schema-extractor
```

The core package has no mandatory dependencies. Some components need optional packages depending on the metadata source you want to use:

```
composer require phpstan/phpdoc-parser
composer require phpdocumentor/reflection-docblock
composer require symfony/validator
composer require symfony/serializer
```

Install only the packages needed by the discoverers, enrichers, or serialization strategies you enable.

Quick Example
-------------

[](#quick-example)

Given a small DTO:

```
final class UserProfile
{
    public function __construct(
        public string $id,

        /** @var list */
        public array $roles = [],

        /** @var array{theme: string, notifications: bool, locale?: string} */
        public array $preferences = [],
    ) {}
}
```

Create an extractor:

```
use Zeusi\JsonSchemaExtractor\Discoverer\ReflectionDiscoverer;
use Zeusi\JsonSchemaExtractor\Enricher\PhpStanEnricher;
use Zeusi\JsonSchemaExtractor\Mapper\StandardJsonSchemaMapper;
use Zeusi\JsonSchemaExtractor\SchemaExtractor;
use Zeusi\JsonSchemaExtractor\Serialization\JsonEncodeSerializationStrategy;

$extractor = new SchemaExtractor(
    new ReflectionDiscoverer(setTitleFromClassName: true),
    [
        new PhpStanEnricher(),
    ],
    new JsonEncodeSerializationStrategy(),
    new StandardJsonSchemaMapper(),
);

$schema = $extractor->extract(UserProfile::class);

echo json_encode($schema, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
```

The resulting schema includes native PHP types from reflection and PHPDoc information read by the enabled enricher, such as list item types and shaped array fields:

```
{
  "type": "object",
  "title": "UserProfile",
  "properties": {
    "id": {
      "type": "string"
    },
    "roles": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "default": []
    },
    "preferences": {
      "type": "object",
      "properties": {
        "theme": {
          "type": "string"
        },
        "notifications": {
          "type": "boolean"
        },
        "locale": {
          "type": "string"
        }
      },
      "required": [
        "theme",
        "notifications"
      ]
    }
  },
  "additionalProperties": false
}
```

For executable examples, see `bin/schema.php`.

Architecture
------------

[](#architecture)

Extraction is intentionally split into separate phases:

1. **Discover** the PHP class model
2. **Enrich** that PHP model with metadata from PHPDoc, attributes, validators, or custom sources
3. **Project** the enriched PHP model into the serialized output shape
4. **Map** the serialized output shape to JSON Schema

When instantiating [`SchemaExtractor`](src/SchemaExtractor.php), choose components according to the metadata you trust and the serializer you actually use at runtime.

Custom behavior can be added by implementing a discoverer, enricher, serialization strategy, or mapper.

Symfony Bundle
--------------

[](#symfony-bundle)

The Symfony bundle registers the built-in components as services. It reduces the boilerplate needed to define extractor pipelines, especially when using Symfony Serializer and Symfony Validator services. Each extractor must explicitly choose the serialization strategy that matches the JSON produced by the application.

See [`docs/symfony-bundle.md`](docs/symfony-bundle.md) for bundle configuration and available Symfony integration details.

Components
----------

[](#components)

### Discoverer

[](#discoverer)

[`ReflectionDiscoverer`](src/Discoverer/ReflectionDiscoverer.php) is the default and currently only discoverer. It creates the baseline PHP model by reading class properties and native PHP types through reflection, optionally using the class short name as the schema title.

To create a custom discoverer implement [`DiscovererInterface`](src/Discoverer/DiscovererInterface.php).

### Enrichers

[](#enrichers)

Enrichers mutate the PHP model before serialization projection. They should merge information where possible and avoid overwriting stronger information with weaker inferred metadata. They run sequentially, so their order can still matter when two enrichers write to the same part of the model.

ComponentUse it whenDocumentation`PhpStanEnricher`To extract high-precision PHPDoc types, including shaped arrays, generics, ranges, and literal types.[`docs/enrichers/phpstan.md`](docs/enrichers/phpstan.md)`PhpDocumentorEnricher`To extract DocBlock summaries, descriptions, examples, deprecation, and PHPDoc types via `phpdocumentor/reflection-docblock`.[`docs/enrichers/phpdocumentor.md`](docs/enrichers/phpdocumentor.md)`SymfonyValidationEnricher`You want Symfony Validator constraints reflected in the schema as requiredness, formats, limits, and collection shapes.[`docs/enrichers/symfony-validation.md`](docs/enrichers/symfony-validation.md)For a side-by-side capability matrix of the two PHPDoc enrichers, see [`docs/enrichers/phpdoc-enricher-comparison.md`](docs/enrichers/phpdoc-enricher-comparison.md).

To create a custom enricher implement [`EnricherInterface`](src/Enricher/EnricherInterface.php).

### Serialization Strategies

[](#serialization-strategies)

Serialization strategies convert the enriched PHP model into the JSON-facing payload consumed by the mapper. They are the right place for output field names, omitted fields, discriminator fields, root payload changes, and serializer-specific normalized types.

ComponentUse it whenDocumentation`JsonEncodeSerializationStrategy`Your JSON payload follows PHP `json_encode()` behavior, including `JsonSerializable` return shapes when documented.[`docs/serialization/json-encode.md`](docs/serialization/json-encode.md)`SymfonySerializerStrategy`Your JSON payload is produced by Symfony Serializer, including groups, serialized names, name converters, and known normalizers.[`docs/serialization/symfony-serializer.md`](docs/serialization/symfony-serializer.md)To create a custom serialization strategy implement [`SerializationStrategyInterface`](src/Serialization/SerializationStrategyInterface.php).

### Mapper

[](#mapper)

[`StandardJsonSchemaMapper`](src/Mapper/StandardJsonSchemaMapper.php) is the default and currently only mapper. It converts the serialized payload model to JSON Schema. By default, class-backed DTOs and enums are collected in reusable definitions and referenced with `$ref`. The emitted definition keyword follows the configured dialect: `definitions` for Draft-7 and `$defs` for Draft 2020-12.

Nested objects and complex structures are handled recursively. With [`ClassReferenceStrategy::Definitions`](src/Mapper/ClassReferenceStrategy.php), class-backed types are emitted once as reusable definitions and reused through `$ref`. Circular references are always broken with `$ref`.

Mapper-level schema policy is configured through [`StandardJsonSchemaMapperOptions`](src/Mapper/StandardJsonSchemaMapperOptions.php):

```
use Zeusi\JsonSchemaExtractor\Mapper\ClassReferenceStrategy;
use Zeusi\JsonSchemaExtractor\Mapper\JsonSchemaDialect;
use Zeusi\JsonSchemaExtractor\Mapper\StandardJsonSchemaMapper;
use Zeusi\JsonSchemaExtractor\Mapper\StandardJsonSchemaMapperOptions;

$mapper = new StandardJsonSchemaMapper(new StandardJsonSchemaMapperOptions(
    dialect: JsonSchemaDialect::Draft202012,
    includeSchemaKeyword: true,
    classReferenceStrategy: ClassReferenceStrategy::Definitions,
));
```

The default dialect is Draft-7 and the root `$schema` keyword is omitted unless `includeSchemaKeyword` is enabled. If you prefer class-backed schemas to be expanded at the usage site, use `ClassReferenceStrategy::Inline`.

To create a custom mapper implement [`JsonSchemaMapperInterface`](src/Mapper/JsonSchemaMapperInterface.php).

Schema Semantics
----------------

[](#schema-semantics)

### `additionalProperties`

[](#additionalproperties)

Class-based object schemas are strict by default: [`SchemaExtractorOptions`](src/SchemaExtractorOptions.php) defaults to `additionalProperties: false`. This is meant to make DTO-shaped schemas describe the known serialized payload, not an open-ended object.

You can override that default per class with [`#[AdditionalProperties(true)]`](src/Attribute/AdditionalProperties.php). Inline object shapes can also carry their own `additionalProperties` value, for example shaped dictionaries or Symfony Validator `Collection` constraints.

Dictionary-style PHPDoc types such as `array` are represented as JSON objects whose `additionalProperties` value is the schema for `T`.

### `required`

[](#required)

`required` means that a field is expected to be present in the serialized payload. It does not mean that the field value cannot be `null`. The extractor does not infer `required` from PHP non-nullable types alone; enrichers and serialization strategies can mark fields as required or optional when their metadata describes payload presence.

Limitations
-----------

[](#limitations)

- Interfaces and abstract/base classes need an explicit strategy, such as Symfony discriminator metadata, to identify possible concrete output shapes
- Some JSON Schema decisions are necessarily conservative. For example, unions are collapsed when safe, but `oneOf` versus `anyOf` cannot always be inferred from PHP types alone

License
-------

[](#license)

This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.

###  Health Score

39

—

LowBetter than 84% of packages

Maintenance97

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity44

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Total

3

Last Release

16d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/573faa69bb56ed78be26666625a82f4f98475884f941ff8a1b4aa33ece878d24?d=identicon)[antonio.turdo](/maintainers/antonio.turdo)

---

Top Contributors

[![antonioturdo](https://avatars.githubusercontent.com/u/1651072?v=4)](https://github.com/antonioturdo "antonioturdo (9 commits)")

---

Tags

phpdocschemajson-schemadtollmsymfony-validatorsymfony-serializerstructured outputasync api

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/zeusi-json-schema-extractor/health.svg)

```
[![Health](https://phpackages.com/badges/zeusi-json-schema-extractor/health.svg)](https://phpackages.com/packages/zeusi-json-schema-extractor)
```

###  Alternatives

[opis/json-schema

Json Schema Validator for PHP

64841.2M257](/packages/opis-json-schema)[wendelladriel/laravel-validated-dto

Data Transfer Objects with validation for Laravel applications

762621.7k17](/packages/wendelladriel-laravel-validated-dto)[geraintluff/jsv4

A (coercive) JSON Schema v4 Validator for PHP

115461.4k4](/packages/geraintluff-jsv4)[ergebnis/json-schema-validator

Provides a JSON schema validator, building on top of justinrainbow/json-schema.

3629.5M7](/packages/ergebnis-json-schema-validator)[romaricdrigon/metayaml

Using \[Yaml|Xml|json\] schemas files to validate \[Yaml|Xml|json\]

103311.2k8](/packages/romaricdrigon-metayaml)[johnstevenson/json-works

Create, edit, query and validate json

272.7M6](/packages/johnstevenson-json-works)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
