Simple components, big superpowers: byjg/serializer and ObjectCopy
In this post I’ll showcase two tiny-but-mighty pieces: the byjg/serializer’s Serialize and ObjectCopy utilities. Together, they make it trivial to convert, reshape, and map data across formats and DTOs.
Introduction
OpenSource ByJG is a toolbox of small, framework-agnostic components you can mix and match as you like. The project leans heavily into the KISS principle (“keep it simple”), prioritizing short, composable libraries over heavyweight frameworks — you can see that spirit across its PHP component catalog and philosophy pages.
Among these, byjg/serializer shines as a pragmatic way to move data between objects, arrays and wire formats (JSON, XML, YAML) — including handy copy/mapping helpers when shapes don’t match 1:1.
It installs with one line:
composer require byjg/serialize
The library converts any object/array/stdClass to array, and then formats that to JSON, XML, YAML, or plain text. It also parses from JSON/YAML/PHP-serialized strings into arrays, and lets you filter/transform fields and even read PHP 8 attributes on the fly. Under the hood, it sticks to lean dependencies (json, symfony/yaml, simplexml). Opensource ByJG
Basic: from anything to anything
Let’s start with a tiny model and go through the everyday moves.
<?php
use ByJG\Serializer\Serialize;
final class User
{
public function __construct(
private int $id,
private string $name,
private ?string $email = null,
) {}
public function getId(): int { return $this->id; }
public function getName(): string { return $this->name; }
public function getEmail(): ?string { return $this->email; }
}
$user = new User(1, 'João', null);
// 1) Object → array
$asArray = Serialize::from($user)->toArray();
// 2) Array → YAML (JSON/XML similar)
$yaml = Serialize::from($asArray)->toYaml();
// 3) PHP’s own serialized string (use PHP core for output)
$phpSerialized = serialize($asArray);
// 4) Back from a PHP-serialized string → array
$backToArray = Serialize::fromPhpSerialize($phpSerialized)->toArray();
The calls above mirror the documented API for converting “from anything to array”, formatting arrays and objects to JSON/XML/YAML, and parsing from JSON/YAML/PHP serialized strings back to arrays.
Another examples:
<?php
use ByJG\Serializer\Serialize;
// From PHP's native serialize()
$serialized = serialize(['a' => 1, 'b' => 2]);
$parsed = Serialize::fromPhpSerialize($serialized)->toArray();
// [ 'a' => 1, 'b' => 2 ]
// From JSON
$json = '{"foo": "bar"}';
$parsedJson = Serialize::fromJson($json)->toYaml();
// foo: bar
// From YAML
$yaml = "foo: bar\nanswer: 42\n";
$parsedYaml = Serialize::fromYaml($yaml)->toJson();
// {"foo":"bar","answer":42}
Useful modifiers at a glance
<?php
use ByJG\Serializer\Serialize;
$result = Serialize::from($customer)
->withDoNotParseNullValues() // drop nulls
->withOnlyString() // coerce values to strings
->withMethodPattern('/([^A-Za-z0-9])/') // customize getter->property mapping
->toArray();
Other outputs
<?php
use ByJG\Serializer\Serialize;
echo Serialize::from(['k' => 'v'])->toJson();
echo Serialize::from(['k' => 'v'])->toXml();
echo Serialize::from(['k' => 'v'])->toPlainText();
Read PHP 8 Attributes and transform values
You can parse attributes and transform each property as you go — a powerful hook for masking, formatting, or adding metadata.
<?php
use ByJG\Serializer\Serialize;
#[Attribute]
final class Label {
public function __construct(public string $text) {}
}
final class Product {
#[Label('SKU')]
public string $id = 'A-123';
#[Label('Pretty name')]
public string $name = 'Fuzzy Panda';
}
$prod = new Product();
$out = Serialize::from($prod)->parseAttributes(
// Callback receives ($attributeInstance, $value, $keyName, $propertyName, $getterName)
function ($attr, $value, $key, $prop, $getter) {
// If the attribute exists, append its label
return $attr ? "{$value} ({$attr->text})" : $value;
},
Label::class // Only parse this attribute type
// , $flags (optional)
);
print_r($out);
// [ 'id' => 'A-123 (SKU)', 'name' => 'Fuzzy Panda (Pretty name)' ]
This callback-based attribute parsing is part of the Serialize API.
ObjectCopy: move data between arrays and objects
ObjectCopy moves data between arrays/objects, even when property names differ. You can rename properties, switch case styles, and alter values on the fly.
Here a basic example:
<?php
use ByJG\Serializer\ObjectCopy;
class UserDto
{
public int $id;
public string $name;
}
$payload = ['id' => 10, 'name' => 'Ana'];
$dto = new UserDto();
ObjectCopy::copy($payload, $dto);
// $dto->id === 10; $dto->name === 'Ana'
And another copying from one DTO into another DTO
<?php
use ByJG\Serializer\ObjectCopy;
class SourceDto { public int $idModel = 1; public string $clientName = 'John'; }
class TargetDto { public int $idModel; public string $clientName; }
$source = new SourceDto();
$target = new TargetDto();
ObjectCopy::copy($source, $target);
Advanced: camelCase to snake_case
<?php
use ByJG\Serializer\ObjectCopy;
use ByJG\Serializer\Property\CamelToSnakeCase;
class Source
{
public int $idModel = 1;
public string $clientName = 'John';
public int $age = 30;
}
class Target
{
public int $id_model;
public string $client_name;
public int $age;
}
$source = new Source();
$target = new Target();
ObjectCopy::copy($source, $target, new CamelToSnakeCase());
Advanced: snake_case to camelCase
<?php
use ByJG\Serializer\ObjectCopy;
use ByJG\Serializer\Property\SnakeToCamelCase;
class Source {
public int $id_model = 1;
public string $client_name = 'John';
public int $age = 30;
}
class Target {
public int $idModel;
public string $clientName;
public int $age;
}
$source = new Source();
$target = new Target();
ObjectCopy::copy($source, $target, new SnakeToCamelCase());
Advanced: map different property names explicitly
<?php
use ByJG\Serializer\ObjectCopy;
use ByJG\Serializer\Property\DifferentTargetProperty;
class Source {
public int $id_model = 1;
public string $client_name = 'John';
public int $age = 30;
}
class Target {
public int $SomeId;
public string $SomeName;
public int $SomeAge;
}
$source = new Source();
$target = new Target();
ObjectCopy::copy(
$source,
$target,
new DifferentTargetProperty([
'id_model' => 'SomeId',
'client_name' => 'SomeName',
'age' => 'SomeAge',
])
);
Advanced: apply value conversions while copying
<?php
use ByJG\Serializer\ObjectCopy;
$payload = [
'birth_date' => '2024-12-31',
'amount' => 123.45,
'name' => 'john',
];
class InvoiceDto
{
public \DateTimeImmutable $birthDate;
public int $amountCents;
public string $name;
}
$target = new InvoiceDto();
$changeValue = function (string $sourceName, string $targetName, $value) {
if ($targetName === 'birthDate') {
return new \DateTimeImmutable($value);
}
if ($targetName === 'amountCents') {
return (int) round($value * 100);
}
if ($targetName === 'name') {
return ucfirst($value);
}
return $value;
};
ObjectCopy::copy($payload, $target, null, $changeValue);
Other special conversion cases
- Provide your own property pattern callback to dynamically match names (prefixes, different setters, etc.).
- Combine a property pattern and a value transformer in the same copy call.
- Use ObjectCopyInterface to add copyFrom/copyTo to your DTOs, so they can ingest/emit data directly.
<?php
use ByJG\Serializer\ObjectCopy;
use ByJG\Serializer\ObjectCopy as ObjectCopyBase; // if you prefer extending
class MyDto extends ObjectCopyBase {}
$dto = new MyDto();
$dto->copyFrom(['id' => 1, 'name' => 'Alice']); // from array/object to this DTO
$dto->copyTo($another); // from this DTO into another object/array
Wrap-up
If you need pragmatic, framework-agnostic data shaping in PHP, byjg/serializer delivers:
- Serialize to read and emit arrays/JSON/YAML/XML and parse PHP-serialized data—with handy modifiers.
- ObjectCopy to move data between arrays and objects, rename or retarget fields, switch case styles, and transform values inline.
Explore the full docs for more patterns and edge cases: