zumba/json-serializer

Serialization of internal classes

eymengunay opened this issue · 6 comments

Serializer throws ReflectionException when class property is an internal class. (For example DateTime class can not be serialized because of this error)

ReflectionClass::newInstanceWithoutConstructor on php.net

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?

We can't apply this rule for all internal classes. stdClass, for example, is an internal class but can be instantiated with newInstanceWithoutConstructor. I couldn't find a method to explicit say if the class can initialized or not with that method. A solution probably would be to try/catch the exception and try to use the unserialize alternative. Or maybe just add an special condition to DateTime. I don't think many internal classes would have the same issue.

You are definitely right, it is not a complete solution. Looking for similar issues I stumbled upon some results from phpunit mock object library. Here is how they resolved it, hope this helps better:

https://github.com/sebastianbergmann/phpunit-mock-objects/pull/174/files

Anyway, also a simple special condition just for DateTime class sounds completely reasonable.

That's interesting, but I did some tests and it doesn't work with DateTime. I guess I will have to put a specific condition to this class for now.

You can see it here:

# Unserializing without the properties
$ php -r 'var_dump(unserialize("O:8:\"DateTime\":0:{}"));'
PHP Fatal error:  Invalid serialization data for DateTime object in Command line code on line 1

# Trying to instantiate the class using reflection
$ php -r '(new ReflectionClass("DateTime"))->newInstanceWithoutConstructor();'
PHP Fatal error:  Uncaught exception 'ReflectionException' with message 'Class DateTime is an internal class that cannot be instantiated without invoking its constructor' in Command line code:1
Stack trace:
#0 Command line code(1): ReflectionClass->newInstanceWithoutConstructor()
#1 {main}
  thrown in Command line code on line 1

# The serialized version that can be unserialized
$ php -r 'var_dump(unserialize('"'"'O:8:"DateTime":3:{s:4:"date";s:19:"2014-06-15 03:43:40";s:13:"timezone_type";i:3;s:8:"timezone";s:3:"UTC";}'"'"'));'
object(DateTime)#1 (3) {
  ["date"]=>
  string(19) "2014-06-15 03:43:40"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(3) "UTC"
}

Thanks for the pr!

PS: I'm not sure if it is better to close the issue (once pr gets merged ofcourse) or keep it open for other possibly similar problems so I'm leaving it to you @jrbasso :)

No problem. Thanks for reporting the issue.

The issue will be automatically closed when the PR is merged.