Map JSON data to strongly-typed PHP classes using Symfony's PropertyInfo and PropertyAccess components.
JsonMapper is a PHP library that maps JSON data to strongly-typed PHP classes (DTOs, value objects, entities) using reflection and PHPDoc annotations. It leverages Symfony's PropertyInfo and PropertyAccess components to provide flexible, extensible JSON-to-PHP object mapping.
| Key | Value |
|---|---|
| Package | magicsunday/jsonmapper |
| PHP | ^8.3 |
| Main API | MagicSunday\JsonMapper |
| Output | Mapped PHP objects + optional MappingReport |
JsonMapper takes decoded JSON (via json_decode) and hydrates typed PHP objects, including nested objects, collections, enums, DateTime values, and custom types. It supports both lenient and strict mapping modes with detailed error reporting.
Mapping API responses or configuration payloads to typed PHP classes is a common task that involves repetitive boilerplate. JsonMapper automates this with a clean, extensible architecture based on Symfony components, supporting advanced scenarios like polymorphic APIs, custom name conversion, and recursive collection handling.
composer require magicsunday/jsonmappernamespace App\Dto;
use ArrayObject;
final class Comment
{
public string $message;
}
/**
* @extends ArrayObject<int, Comment>
*/
final class CommentCollection extends ArrayObject
{
}
/**
* @extends ArrayObject<int, Article>
*/
final class ArticleCollection extends ArrayObject
{
}
final class Article
{
public string $title;
/**
* @var CommentCollection<int, Comment>
*/
public CommentCollection $comments;
}require __DIR__ . '/vendor/autoload.php';
use App\Dto\Article;
use App\Dto\ArticleCollection;
use MagicSunday\JsonMapper;
$single = json_decode('{"title":"Hello world","comments":[{"message":"First!"}]}', associative: false, flags: JSON_THROW_ON_ERROR);
$list = json_decode('[{"title":"Hello world","comments":[{"message":"First!"}]},{"title":"Second","comments":[]}]', associative: false, flags: JSON_THROW_ON_ERROR);
$mapper = JsonMapper::createWithDefaults();
$article = $mapper->map($single, Article::class);
$articles = $mapper->map($list, Article::class, ArticleCollection::class);JsonMapper::createWithDefaults() wires the default Symfony PropertyInfoExtractor (reflection + PhpDoc) and a PropertyAccessor. For custom extractors, caching, or a specialised accessor see Manual instantiation.
Annotate all properties with the requested type. For collections, use the phpDocumentor collection annotation type:
/** @var SomeCollection<DateTime> $dates */
/** @var SomeCollection<string> $labels */
/** @var Collection\\SomeCollection<App\\Entity\\SomeEntity> $entities */- API reference
- Recipes
- Manual instantiation β custom extractors, name converters, class maps, collection mapping
- Type converters and custom class maps β custom type handlers, runtime class resolution
- Error handling strategies β strict vs. lenient mode, error collection
- Performance hints β PSR-6 type caching
- Using mapper attributes β ReplaceProperty, ReplaceNullWithDefaultValue
- Mapping JSON to PHP enums
- Mapping nested collections
- Using a custom name converter
Prerequisites:
- PHP
^8.3 - Extensions:
json
Install dependencies:
composer installRun the mandatory quality gate:
composer ci:testci:test includes:
- Linting (
phplint) - Unit tests (
phpunit) - Static analysis (
phpstan) - Refactoring dry-run (
rector --dry-run) - Coding standards dry-run (
php-cs-fixer --dry-run) - Copy/paste detection (
jscpd)
See CONTRIBUTING.md for contributor workflow and minimal setup.
If contributions are prepared or modified by an LLM/agent, follow AGENTS.md.