jms/serializer
2.0
Asmir Mustafic
Symfony User Group - Berlin - October 2018
You?
Me
Asmir Mustafic
Me
@goetas
- Twitter: @goetas_asmir
- Github: @goetas
- LinkedIn: @goetas
- WWW: goetas.com
Me
Software Developer
Berlin
Me
index.php ~2001
index.html ~1999
My first
Open source
- jms/serializer (contributor/maintainer)
- masterminds/html5 (contributor/maintainer)
- hautelook/templated-uri-bundle (contributor/maintainer)
- goetas-webservices/xsd2php (author)
- goetas-webservices/xsd-reader (author)
- goetas-webservices/soap-client (author)
- goetas/twital (author)
- doctrine/orm (occasional contributor)
- nelmio/api-doc (occasional contributor)
- many others...
Serializer?
jms/serializer?
class User
{
private $name;
private $email;
public function __construct($name, $email)
{
$this->name = $name;
$this->email = $email;
}
}
$user = new User(
'Elvis Presley',
'elvis@rocknroll.com'
);
// or get it from DB
echo $serializer->serialize($user);
{
"name": "Elvis Presley",
"email": "elvis@rocknroll.com"
}
json_encode
json_decode
JsonSerializable
class User implements JsonSerializable
{
// ...
public function jsonSerialize()
{
return [
"name" => $this->name,
"email" => $this->email,
];
}
}
echo json_encode($user);
{
"name": "Elvis Presley",
"email": "elvis@rocknroll.com"
}
Show the email
only to
logged-in users?
class User implements JsonSerializable
{
// ...
public function jsonSerialize()
{
if (Auth::getInstance()->isLoggedIn()) {
return [
"name" => $this->name,
"email" => $this->email,
];
} else {
return [
"name" => $this->name,
];
}
}
}
PHP
Serialize:
- JSON
- XML
Deserialize:
- JSON
- XML
jms/serializer
opensource
First release 2011
Features?
Metadata:
- XML
- YAML
- Annotations
- Custom drivers
Serialize into:
- XML
- JSON
Deserialize from:
- XML
- JSON
Exclusion strategies:
- per-class
- groups
- nested groups
- max-depth
- expression-language
- versioning
- custom
Customization:
- custom events
- custom handlers
Access strategies:
- virtual-properties
- reflection
- getter/setter
- closure bind
- expression-language
More:
- XML Namespaces
- Custom access order
- Read-Only properties
- Inheritance Support
- Doctrine Support
And More:
- Fast
- Battle tested
Naming:
- multiple built-in strategies
- custom strategies
Features
https://slides.com/goetas/jms-serializer-2017
jms/serializer
2.0
PHP ^5.5 || ^7.0
Apache-2 License
Serialize:
- JSON
- XML
- YAML
Deserialize:
- JSON
- XML
jms/serializer
1.x
opensource
PHP ^5.5 || ^7.0 ^5.5 ^7.2
Apache-2 License MIT
Serialize:
- JSON
- XML
YAML
Deserialize:
- JSON
- XML
jms/serializer
2.0
opensource
jms/serializer
Why upgrade?
~20-50% faster
Less
Accumulated in 7 years of history
bugs
workarounds edge-cases
How to upgrade?
Backward compatible
Almost...
Same
metadata
format
YAML/XML/Annotations
Same
listeners
format
Same
handlers
format
Almost
~20-50% faster
Lets go back to...
Benchmarks
Benchmark your application
Developer productivity
Not just serialization performance!
Benchmarks
egeloen/ivory-serializer-benchmark
Vertical Complexity
Horizontal Complexity
Vertical Complexity
Horizontal Complexity
Vertical and Horizontal
Vertical and Horizontal x2
The initialization
takes more time
than the serialization
With small datasets
v2.0 Changes
109 issues closed
246 commits
533 files changed
26 months
MIT
license
211 contributor
approvals
Technical Improvements
Huge Internal refactoring
no impact on user API
Simpler context
$context = SerializationContext::create();
// v1.x
$context->attributes->set("foo", "bar");
$holder = $context->attributes->get("foo");
if ($holder instanceof Some) {
// get a value
$value = $holder->get();
}
Simpler context
$context = SerializationContext::create();
// v2.0
$context->setAttribute("foo", "bar");
if ($context->hasAttribute("foo")) {
// get a value
$value = $context->getAttribute("foo");
}
Max Depth
class User
{
private $name;
/**
* @MaxDepth(1)
* @var Collection|Song[]
*/
private $songs;
}
{
"name": "Elvis Presley",
"songs": {
{},
{}
}
}
Max Depth v 1.x
Max Depth v 1.x
class User
{
private $name;
/**
* @MaxDepth(2)
* @var Collection|Song[]
*/
private $songs;
}
{
"name": "Elvis Presley",
"songs": {
{
"id: 9
"title: "Jailhouse Rock"
},
{
"id: 10
"title: "Love me tender"
}
}
}
Max Depth
Max Depth v 2.0
class User
{
private $name;
/**
* @MaxDepth(1)
* @var Collection|Song[]
*/
private $songs;
}
{
"name": "Elvis Presley",
"songs": {
{
"id: 9
"title: "Jailhouse Rock"
},
{
"id: 10
"title: "Love me tender"
}
}
}
Max Depth
Type Handlers
function ($visitor, $data)
{
// do something
return $result;
}
It's just a callback!
function ($visitor, $data, $type, $context)
{
// do something
return $result;
}
Type Handlers v 1.x
function (
JsonSerializationVisitor $visitor,
User $user
)
{
$data = [
'username' => $user->getUsername()
];
// extra root check
if ($visitor->getRoot() === null) {
$visitor->setRoot($data);
}
return $data;
}
Type Handlers v 2.0
function (
JsonSerializationVisitor $visitor,
User $user
)
{
return [
'username' => $user->getUsername()
];
}
Recursive Calls
class CustomUserHandler
{
function __construct(Serializer $serializer)
{
$this->serializer = $serializer;
}
function serializeUserToJson(
JsonSerializationVisitor $visitor,
User $user
)
{
return [
'raw' => $this->serializer->serialize($user, 'json')
];
}
}
Extensibility
Most of the classes now are declared
final
use composition
inheritance is evil
https://ocramius.github.io/blog/when-to-declare-classes-final/
Error Handling
JMS\Serializer\Exception\InvalidMetadataException
All metadata errors throw a single exception type
Symfony Support?
JMSSerializerBundle
JMSSerializerBundle
v3.0
jms_serializer:
visitors:
json_serialization:
options: 0 # json_encode options bitmask
depth: 512
json_deserialization:
options: 0 # json_dencode options bitmask
jms_serializer:
visitors:
xml_serialization:
format_output: false
version: "1.0"
encoding: "UTF-8"
default_root_name: "result"
default_root_ns: null
xml_deserialization:
external_entities: false
doctype_whitelist:
- '<!DOCTYPE authorized ...'
Now is your turn!
{
"require" : {
"jms/serializer" : "^2.0"
},
"minimum-stability": "RC"
}
{
"require" : {
"jms/serializer-bundle" : "^3.0"
},
"minimum-stability": "RC"
}
Thank you!
Please leave a feedback
Twitter: @goetas_asmir
Comment on: sfugberlin
jms/serializer v2.0 is behind the corner
By Asmir Mustafic
jms/serializer v2.0 is behind the corner
After more than a two years of work, jms/serializer v2.0 is going to see the light. You will get a preview of the changes, new features and improvements that will be released soon.
- 1,726