Depuis PHP 8.2, c'est devenu un vrai bonheur de coder des Dtos, des entities, des Value Object, ... car le code peut être beaucoup moins verbeux et beaucoup plus strict.
Exemple de Value Object immutable :
final readonly class Coordinate
{
public function __construct(
public float $latitude,
public float $longitude,
) {
}
}
// Instantiation "magique" depuis un array.
$coord = Coordinate(...['latitude' => 1.5, 'longitude' => 40.5]);
Exemple d'entity avec sous object auto-construit :
enum Gender
{
case Male;
case Female;
case Other;
}
final readonly class User
{
public function __construct(
public int $id,
public string $name,
public null|Gender $gender = null,
public DateTimeImmutable $createdAt = new DateTimeImmutable(),
) {
}
}
// Pas besoin de renseigner $createdAt : il sera auto instantié (new en default).
$user = new User(1, 'Arnaud');
Besoin
Pour plusieurs projets perso, j'ai besoin de consommer des Apis JSON, à chaque fois, les phases de validation (Json-schema, manuel, ...) à base d'array etc ... sont très consommatrices de temps et fastitieuses.
Mon idée, c'est de créer des structures complètes d'objets modernes, immutables si possible, à partir du json de ces apis : cela fait de facto office de validation et me permet d'utiliser des objets propres, auto-documentés, etc ...
Il existe déjà pas mal de lib qui savent faire plus ou moins ce genre de choses, je pense par exemple à symfony/serializer.

Quel est mon problème avec ces libs ?
- Elles imposent de modifier les objets pour que la magie opère (abstract, attributes, ...).
- Elles permettent de faire des opérations dangereuses (modification de private via reflection, appels magiques de setters, ...).
Mon besoin
- 100% respect du contrat des objets : zéro hack, créer l'objet comme un code naturel le ferait.
- Pas de symétrie imposée entre array vers object ou object vers array.
- Pas de modification imposée à vos objets : ils peuvent rester 100% dans votre domaine, vos conversions sont du ressort de l'infrastructure (cf. clean architecture).
Exemple :
$converter = new \Arnapou\Dto\DtoConverter();
$object = $converter->fromdata($array, MaClasse::class);
$array = $converter->toData($object);
La lib fournit de base un DtoConverter
"tout en un" qui est suffisant pour démarrer.
Ce dernier sait gérer de base :
- Le type
stdClass
(propriétés dynamiques) - Les enums
- Les
DateTimeInterface
(DateTime
etDateTimeImmutable
) - Les classes comme celles en exemple plus haut (Value Object, Dto, Entity) grâce à la réflexion
- Les collections d'objets (cf.
CollectionConverter
) si vous étendez par flemmeAbstractCollection
, mais vous rendez vos objets dépendants de la lib, c'est pas ouf.
Vous pouvez implementer vous-même vos DataConverter
et gérer vos objets particuliers.
C'est très ouvert.
Détails
Pour plus de détails techniques, allez voir le README sur Gitlab.