zumba / json-serializer Goto Github PK
View Code? Open in Web Editor NEWSerialize PHP variables, including objects, in JSON format. Support to unserialize it too.
Home Page: http://tech.zumba.com/2014/01/06/json-serializer/
License: MIT License
Serialize PHP variables, including objects, in JSON format. Support to unserialize it too.
Home Page: http://tech.zumba.com/2014/01/06/json-serializer/
License: MIT License
Thank you for this nice light-weight library - I use it a lot for testing purposes π
With version 3.1.0, serialization has stopped working under PHP 7.1 due to using an unsupported feature:
Fatal error: Dynamic class names are not allowed in compile-time ::class fetch in zumba/json-serializer/src/JsonSerializer/JsonSerializer.php
on line 266
'::class' on objects is only allowed since PHP 8.0
When you change the locale (using, for example, setlocale(LC_ALL, "fr_FR")
in your PHP code), the conversion of floats are made in the locale (for France, using ",
" instead of ".
" for decimal point). Then if the variable $preserveZeroFractionSupport is set to true
, there is an encoding issue.
I found this workaround forcing the formatting only in specific cases:
if (!$this->preserveZeroFractionSupport && is_float($value) && abs($value) < 1e+10 && abs($value) > 0.01 ) {
// Because the PHP bug #50224, the float numbers with no
// precision numbers are converted to integers when encoded
// Notice the following will not be sensible to locale.
$value = static::FLOAT_ADAPTER . '(' . number_format($value, 6, ".", "" ) . ')';
}
Instead of wasting CPU cycles in JsonSerializer::calculateEncodeOptions()
, just use numeric value.
1856 == JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR | JSON_PRESERVE_ZERO_FRACTION
or
1344 == JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION
when I have:
<?php
declare(strict_types=1);
namespace App\Model;
abstract class AbstractModel // This need not be a abstract
{
private $abstractPrivateProperty;
public $abstractPublicProperty;
protected $abstractProtectedProperty;
public function __construct()
{
$this->abstractPrivateProperty = 'private';
$this->abstractPublicProperty = 'public';
$this->abstractProtectedProperty = 'protected';
}
/**
* @return string
*/
public function getAbstractPrivateProperty(): string
{
return $this->abstractPrivateProperty;
}
}
class MainModel extends AbstractModel
{
public $publicProperty;
private $privateProperty;
protected $protectedProperty;
public function __construct()
{
$this->publicProperty = 'public';
$this->privateProperty = 'private';
$this->protectedProperty = 'protected';
parent::__construct();
}
}
and then I try:
<?php
require_once __DIR__ . '/vendor/autoload.php';
$model = new \App\Model\MainModel();
var_dump($model->getAbstractPrivateProperty()); // returns string(7) "private"
$serializer = new \Zumba\JsonSerializer\JsonSerializer();
$serialized = $serializer->serialize($model);
var_dump($serialized); // returns string(193) "{"@type":"App\\Model\\MainModel","publicProperty":"public","privateProperty":"private","protectedProperty":"protected","abstractPublicProperty":"public","abstractProtectedProperty":"protected"}"
/** @var \App\Model\MainModel $back */
$back = $serializer->unserialize($serialized);
var_dump($back);
/** returns
class App\Model\MainModel#11 (6) {
public $publicProperty =>
string(6) "public"
private $privateProperty =>
string(7) "private"
protected $protectedProperty =>
string(9) "protected"
private $abstractPrivateProperty =>
NULL
public $abstractPublicProperty =>
string(6) "public"
protected $abstractProtectedProperty =>
string(9) "protected"
}
*/
var_dump($back->getAbstractPrivateProperty()); // PHP Fatal error: Uncaught TypeError: Return value of App\Model\AbstractModel::getAbstractPrivateProperty() must be of the type string, null returned
so method getAbstractPrivateProperty
returns null after unserialize.
I think its, bug or not ?
I believe the serializer should be able to handle non UTF8 data. Using a serializer in a messaging system should not limit the type of data you throw at it: what goes in on one side should come out exactly like that on the other side.
I am currently implementing this feature making heavy use of the mbstring extension (for detecting the string encoding and doing conversions). The idea is that whenever I encounter a string that is not UTF8 encoded, I assume it as being with 8bit encoding, convert it to UTF8 on serialization and then convert it back from UTF8 to 8bit during deserialization. This way, if junk comes in, junk comes out without any modifications.
In principle, would you accept such a pull request, or do you have a different vision regarding the capabilities of this library? I'm asking because if you are not interested in this feature I will prefer to internalize this library (a refactored version of it) into my project instead of building it onto the existing code.
Description
When I implement the readme example of Serializing Closures
on PHP 8.1.12, I get this ErrorException.
SuperClosure\SerializableClosure implements the Serializable interface, which is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary)
Does it need to change the depency of SuperClosure
to Opis Closure
(Maybe the superClosure repo is no longer maintained) to support the closures requirement?
Thanks.
jeremeamia/superclosure is being used on the project and it is abandoned. We should use https://packagist.org/packages/opis/closure instead.
To avoid issues with stored data, the code must support both libraries, where the unserialize can read for either library, but the serialize only writes using the new closure library.
Not sure the best way to add this while supporting backwards compatibility.
https://wiki.php.net/rfc/precise_float_value
This test fails in PHP7.1+:
$data = [1.0, 1.1, 0.00000000001, 1.999999999999, 223423.123456789, 1e5, 1e11];
$expected = '[1.0,1.1,1.0e-11,1.999999999999,223423.12345679,100000.0,100000000000.0]';
$this->assertSame($expected, $this->serializer->serialize($data));
1) Zumba\JsonSerializer\Test\JsonSerializerTest::testSerializeFloatLocalized
Failed asserting that two strings are identical.
--- Expected
+++ Actual
@@ @@
-[1.0,1.1,1.0e-11,1.999999999999,223423.12345679,100000.0,100000000000.0]
+[1.0,1.1,1.0e-11,1.999999999999,223423.123456789,100000.0,100000000000.0]
Hi,
Both Enum types canβt be deserialized and create a fatal error : Fatal error: Uncaught Error: Cannot instantiate enum ...
I think they could be both managed into unserializeObject
method by adding :
if (is_subclass_of($className, \BackedEnum::class) || is_subclass_of($className, \UnitEnum::class)) {
return constant("$className::{$value['name']}");
}
Hope it helps :)
To reproduce:
$serializer = new \Zumba\JsonSerializer\JsonSerializer();
echo $serializer->serialize(new \DateTime()) . "\n";
echo $serializer->serialize(new \DateTimeImmutable()) . "\n";
Expected output (as in PHP up to 7.3):
{"@type":"DateTime","date":"2020-06-11 19:20:05.099012","timezone_type":3,"timezone":"Europe\/Berlin"}
{"@type":"DateTimeImmutable","date":"2020-06-11 19:20:05.099087","timezone_type":3,"timezone":"Europe\/Berlin"}
Actual output (in PHP 7.4.5):
{"@type":"DateTime"}
{"@type":"DateTimeImmutable"}
Serializer throws ReflectionException
when class property is an internal class. (For example DateTime
class can not be serialized because of this error)
As a temporary solution I've added a if ($ref->isInternal())
check with newInstance
method and it seems to work fine.
Do you have any other ideas on how to fix the problem?
Try to make this library compatible with Symfony's serializer project: http://symfony.com/doc/current/components/serializer.html
First, thanks for your effective and simple to use library.
During unserialization if a property does not exist on target object : the JsonSerializer will try to set an extra attribute to object
try {
$propRef = $ref->getProperty($property);
$propRef->setAccessible(true);
$propRef->setValue($obj, $this->unserializeData($propertyValue));
} catch (ReflectionException $e) {
$obj->$property = $this->unserializeData($propertyValue);
}
We should manage other mode ($extraAttributeManagementMode):
There is a problem with Non UTF-8 Characters.
Anything Non UTF-8 being passed to the json_encode throws warnings.
Either need to specify in the documentation that binary properties are not supported, or need to add detection and bin2hex
.
Hi
Some deprecated are shown when unserializing a DateTimeImmutable object, like :
Creation of dynamic property DateTimeImmutable::$date is deprecated (in JsonSerializer.php on line 463)
I think this could be treated like DateTime object, on unserializeObject()
method like
if ($className === 'DateTime' || $className === 'DateTimeImmutable') {
$obj = $this->restoreUsingUnserialize($className, $value);
$this->objectMapping[$this->objectMappingIndex++] = $obj;
return $obj;
}
Hope it helps :)
We currently have a special condition for DateTime
class, but looking at the project forks people are also extending it MongoId
and MongoDate
. Having an easier way to customize it would be ideal to avoid forks and customization diverging the project.
An idea would be making JsonSerializer
receive a list of classname with callable to generate the output. It would be used on the unserialize portion. The current DateTime
customization would live in this project since it is a php-core class. People could add it on demand.
Update docs to explain how to implement these customizations too and how to use.
Normalizing/denormalizing (converting from object to/from array) and encoding/decoding (converting from array to/from string) are separate concerns. With the introduction of support for binary data the code inflated by quite a bit and has become had to manage. As such, I opted to follow the pattern used in the Symfony Serializer when I refactored the serializer to be used in my library. Here are the three main files that resulted:
In my code I stripped out the bit of functionality that deals with scalars because I'm only dealing with objects, but you get the point.
It wouldn't be a great effort to apply the same to zumba/json-serializer, but it would break BC compatibility so it would need to bump to version 3.x. You could also consider transforming this library to leverage the Symfony Serializer and just implement an encoder and a normalizer for it. This could potentially open a larger user base for it, as IMO the current normalizers used by the Symfony Serializer are useless.
What do you think?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.