Festi De/Serialization
Deserializes JSON (or a pre-decoded PHP array) into a typed PHP object driven by the #[JsonProperty] attribute.
Requirements: PHP 8.0+, ext-json. No runtime dependencies.
Quick start
use core\json\Deserialize;
use core\json\JsonProperty;
class UserProfile
{
#[JsonProperty("first_name")]
private string $_firstName;
#[JsonProperty("age")]
private int $_age;
public function getFirstName(): string
{
return $this->_firstName;
}
public function getAge(): int
{
return $this->_age;
}
}
$json = '{"first_name": "Alice", "age": 30}';
$profile = Deserialize::toObject($json, UserProfile::class);
// $profile->getFirstName() === "Alice"
The #[JsonProperty] attribute
#[JsonProperty(name: string = '', isRequired: bool = false, description: string = '')]
| Argument | Default | Meaning |
|---|---|---|
name |
'' |
The JSON key to read. When empty, the reflected property or parameter name is used as-is. On setter methods a name is required — omitting it throws JsonPropertyException. |
isRequired |
false |
When true, deserialization throws JsonPropertyException if the key is missing from the input. |
description |
'' |
Free-form metadata for downstream schema generators. Has no effect on deserialization. |
Properties without #[JsonProperty] are ignored unless the JSON key happens to match the property name exactly and you add the attribute without a name.
Three injection patterns
A single class can mix all three patterns. Constructor parameters run first, then property injectors, then method injectors.
1. Property injection
Annotate the property directly. Public, protected, and private properties all work.
class Article
{
#[JsonProperty("title")]
private string $_title;
// Attribute without a name → uses the property name "score" as the JSON key
#[JsonProperty]
protected int $score;
// No attribute → this property is skipped during deserialization
public string $ignored;
}
$article = Deserialize::toObject('{"title":"Hello","score":42}', Article::class);
2. Constructor injection
Use promoted or typed constructor parameters when the class requires immutability or a specific construction order. Constructor parameters without a default value are automatically treated as required.
class Point
{
public function __construct(
#[JsonProperty("x")] private float $_x,
#[JsonProperty("y")] private float $_y
) {}
public function getX(): float
{
return $this->_x;
}
public function getY(): float
{
return $this->_y;
}
}
$point = Deserialize::toObject('{"x": 1.5, "y": 2.0}', Point::class);
3. Setter method injection
Annotate a public method when the JSON key does not correspond to any property name, or when you need to run logic on assignment. The method must accept exactly one parameter.
class Order
{
private int $_idOrder;
#[JsonProperty("id_order")]
public function setOrderID(int $id): void
{
$this->_idOrder = $id;
}
public function getOrderID(): int
{
return $this->_idOrder;
}
}
$order = Deserialize::toArrayObject(['id_order' => 99], Order::class);
Nested objects
When a property or parameter has a class type hint, deserialization recurses automatically into that class.
class Address
{
#[JsonProperty("city")]
private string $_city;
public function getCity(): string
{
return $this->_city;
}
}
class Customer
{
#[JsonProperty("name")]
private string $_name;
#[JsonProperty("address")]
private Address $_address;
public function getName(): string
{
return $this->_name;
}
public function getAddress(): Address
{
return $this->_address;
}
}
$json = '{"name": "Bob", "address": {"city": "Kyiv"}}';
$customer = Deserialize::toObject($json, Customer::class);
// $customer->getAddress()->getCity() === "Kyiv"
API reference
// Deserialize a JSON string into an instance of $className.
Deserialize::toObject(string $json, string $className): object
// Deserialize a pre-decoded PHP array into an instance of $className.
Deserialize::toArrayObject(array $data, string $className): object
Both methods throw core\json\JsonPropertyException when a required field is missing or a method-level #[JsonProperty] has no name.
Schema generation
The description argument of #[JsonProperty] is exposed via DeserializeMapper::getProperties(), which returns an array of PropertyOptions objects. Use this to generate JSON schemas or API documentation from your PHP classes without extra annotation libraries.
use core\json\DeserializeMapper;
use core\json\JsonProperty;
class Product
{
#[JsonProperty("sku", true, "Unique product identifier")]
private string $_sku;
#[JsonProperty("price", false, "Price in USD")]
private float $_price;
}
$mapper = new DeserializeMapper(Product::class);
foreach ($mapper->getProperties() as $options) {
// $options->getName() → "sku" / "price"
// $options->getType() → "string" / "float"
// $options->isRequired() → true / false
// $options->isNullable() → bool
// $options->isObject() → bool (true for class-typed properties)
// $options->getDescription() → "Unique product identifier" / "Price in USD"
}