can't reflection on DateTime properties?

php.internals

Rasmus Schultz

10 years ago
I wrote a library that can serialize/unserialize PHP object graphs to JSON data. Somebody reported it doesn't work on the DateTime class. Does this deliberately not work? $date = new DateTime(); var_dump($date); outputs: object(DateTime)#1 (3) { ["date"]=> string(19) "2016-06-04 19:30:19" ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" } however, this... $reflection = new ReflectionClass('DateTime'); var_dump($reflection->getProperties()); outputs: array(0) { } The object clearly has properties corresponding to it's internal state, but reflection doesn't seem to report them? Also, what comes out of var_dump() appears to be something intended for human consumption? I'm guessing that's not the actual internal state of the object - most likely the internal state consists of the "timezone_type" and an integer timestamp?

Jordi Boggiano

10 years ago
On 04/06/2016 20:36, Rasmus Schultz wrote:
> I wrote a library that can serialize/unserialize PHP object graphs to JSON > data. > > Somebody reported it doesn't work on the DateTime class. > > Does this deliberately not work? > > $date = new DateTime(); > > var_dump($date); > > outputs: > > object(DateTime)#1 (3) { > ["date"]=> > string(19) "2016-06-04 19:30:19" > ["timezone_type"]=> > int(3) > ["timezone"]=> > string(3) "UTC" > } > > however, this... > > $reflection = new ReflectionClass('DateTime'); > > var_dump($reflection->getProperties()); > > outputs: > > array(0) { > } > > The object clearly has properties corresponding to it's internal state, but > reflection doesn't seem to report them?
I can't tell you why it acts like this, but in case you are looking for a workaround: https://3v4l.org/V5cfl Cheers
-- Jordi Boggiano @seldaek - http://seld.be

Eugene Leonovich

10 years ago
On Sat, Jun 4, 2016 at 9:42 PM, Jordi Boggiano <j.boggiano@seld.be> wrote:
> On 04/06/2016 20:36, Rasmus Schultz wrote: > >> I wrote a library that can serialize/unserialize PHP object graphs to JSON >> data. >> >> Somebody reported it doesn't work on the DateTime class. >> >> Does this deliberately not work? >> >> $date = new DateTime(); >> >> var_dump($date); >> >> outputs: >> >> object(DateTime)#1 (3) { >> ["date"]=> >> string(19) "2016-06-04 19:30:19" >> ["timezone_type"]=> >> int(3) >> ["timezone"]=> >> string(3) "UTC" >> } >> >> however, this... >> >> $reflection = new ReflectionClass('DateTime'); >> >> var_dump($reflection->getProperties()); >> >> outputs: >> >> array(0) { >> } >> >> The object clearly has properties corresponding to it's internal state, >> but >> reflection doesn't seem to report them? >> > > I can't tell you why it acts like this, but in case you are looking for a > workaround: https://3v4l.org/V5cfl > > Cheers > > -- > Jordi Boggiano > @seldaek - http://seld.be > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > >
The simplified workaround is to cast a DateTime object to an array: https://3v4l.org/DESiq

Nikita

10 years ago
On Sat, 04 Jun 2016 22:36:19 +0300, Rasmus Schultz <rasmus@mindplay.dk> wrote:
> I wrote a library that can serialize/unserialize PHP object graphs to > JSON > data. > > Somebody reported it doesn't work on the DateTime class. > > Does this deliberately not work? > > $date = new DateTime(); > > var_dump($date); > > outputs: > > object(DateTime)#1 (3) { > ["date"]=> > string(19) "2016-06-04 19:30:19" > ["timezone_type"]=> > int(3) > ["timezone"]=> > string(3) "UTC" > } > > however, this... > > $reflection = new ReflectionClass('DateTime'); > > var_dump($reflection->getProperties()); > > outputs: > > array(0) { > } > > The object clearly has properties corresponding to it's internal state, > but > reflection doesn't seem to report them? > > Also, what comes out of var_dump() appears to be something intended for > human consumption? I'm guessing that's not the actual internal state of > the > object - most likely the internal state consists of the "timezone_type" > and > an integer timestamp?
Yes, DateTime/DateTimeImmutable classes define custom `get_properties` zend_class_entry handler: http://lxr.php.net/xref/PHP_MASTER/ext/date/php_date.c#2162 Which is called whenever you `var_dump()` it or foreach over the object or call a `get_object_vars()` on it: https://3v4l.org/tNJXN But reflection on the other hand directly uses `zend_class_entry->properties_info` table which DateTime does not have: http://lxr.php.net/xref/PHP_MASTER/ext/reflection/php_reflection.c#4574

Stas Malyshev

10 years ago
Hi!
> The object clearly has properties corresponding to it's internal state, but > reflection doesn't seem to report them?
Reflection reports defined properties, but classes can have dynamic properties that are not pre-defined. var_dump also has a separate handler, so the object can present different information to var_dump.
> Also, what comes out of var_dump() appears to be something intended for > human consumption? I'm guessing that's not the actual internal state of the > object - most likely the internal state consists of the "timezone_type" and > an integer timestamp?
In generic case, you can't have internal state of an object, that's why it's internal. If you need to serialize data, there are serialize/unserialize handlers for it.
-- Stas Malyshev smalyshev@gmail.com

Rasmus Schultz

10 years ago
> In generic case, you can't have internal state of an object, that's why it's
internal I know that things like internal state and read-only properties are possible for classes written in C, but those features aren't possible in PHP code - classes that behave this way are inconsistent with classes written in the language, and it becomes a problem in cases such as this.
> If you need to serialize data, there are serialize/unserialize handlers
for it. That is no help at all, when you're implementing a JSON serializer. You can see the class in question here: https://github.com/mindplay-dk/jsonfreeze/blob/master/mindplay/jsonfreeze/JsonSerializer.php Because DateTime does not behave like other classes, the only work-around is to explicitly handle DateTime with an if/instanceof-statement and handle that particular class explicitly. There are plenty of work-arounds - the point is that this class doesn't behave consistently with any other PHP class. On Sat, Jun 4, 2016 at 10:23 PM, Stanislav Malyshev <smalyshev@gmail.com> wrote:

Fleshgrinder

10 years ago
On 6/4/2016 11:05 PM, Rasmus Schultz wrote:
> I know that things like internal state and read-only properties are > possible for classes written in C, but those features aren't possible in > PHP code - classes that behave this way are inconsistent with classes > written in the language, and it becomes a problem in cases such as this. > > That is no help at all, when you're implementing a JSON serializer. > > You can see the class in question here: > > https://github.com/mindplay-dk/jsonfreeze/blob/master/mindplay/jsonfreeze/JsonSerializer.php > > Because DateTime does not behave like other classes, the only work-around > is to explicitly handle DateTime with an if/instanceof-statement and handle > that particular class explicitly. > > There are plenty of work-arounds - the point is that this class doesn't > behave consistently with any other PHP class. >
I have to fully agree with Rasmus here. This is one of those unnecessary WTF moments for users that forces them to implement work arounds instead of simply writing good software.
-- Richard "Fleshgrinder" Fussenegger

Stas Malyshev

10 years ago
Hi!
> I know that things like internal state and read-only properties are > possible for classes written in C, but those features aren't possible in > PHP code - classes that behave this way are inconsistent with classes
Of course they are possible. See __get/__set. But yes, internal classes work a bit differently, which is no wonder since they can use internal handlers which are not available to PHP code.
> That is no help at all, when you're implementing a JSON serializer.
Right, DateTime does not implement Serializable. Probably might be a good idea to make it do that. Otherwise - though in general it is not a very good idea to serialize objects which didn't declare they are serializeable, especially internal ones. But if one feels adventurous the handler to use would be get_properties, and converting to array uses this handler, so you could do that. It's the same handler serializers use to get properties, unless Serializable is implemented or __sleep is defined.
> Because DateTime does not behave like other classes, the only > work-around is to explicitly handle DateTime with an > if/instanceof-statement and handle that particular class explicitly. > > There are plenty of work-arounds - the point is that this class doesn't > behave consistently with any other PHP class.
It does. It's just PHP classes can behave in more ways than you think :) And to some of the ways there's no good access from PHP space.
-- Stas Malyshev smalyshev@gmail.com

Rasmus Schultz

10 years ago
> Of course they are possible. See __get/__set
Not the same thing at all - PDOStatement::$queryString is a read-only property, which cannot be overridden, not even with __get() as you would be able to for regular __get() in a regular PHP class. It's also impossible to write a PHP class with "internal state" - state that I can't find at run-time with reflection. That's what makes the language reflective. Internal state in this sense is something foreign to PHP as well, the only exception being things like resources, but those aren't really types in the first place, but handles to file-system objects, representing state outside of the program. We're talking about a simple object representing an integer timestamp and a timezone ID. There is no logical reason those should be hidden - it's just an implementation detail showing up as an artifact.
> It does. It's just PHP classes can behave in more ways than you think :) > And to some of the ways there's no good access from PHP space.
You're describing implementation details - these are features of C, not features of the PHP language, they happen to leak into the into the PHP language where they present themselves as inconsistencies. The fact is that DateTime does not behave like a PHP class in terms of reflection. PHP being a reflective language, that's a language inconsistency. What else would you call it? On Sun, Jun 5, 2016 at 12:59 AM, Stanislav Malyshev <smalyshev@gmail.com> wrote:

Stas Malyshev

10 years ago
Hi!
> It's also impossible to write a PHP class with "internal state" - state > that I can't find at run-time with reflection. That's what makes the > language reflective. Internal state in this sense is something foreign > to PHP as well, the only exception being things like resources, but > those aren't really types in the first place, but handles to file-system > objects, representing state outside of the program.
It's not foreign to PHP, it's unavailable to userspace, yes. Internal functions have access to more capabilities than userspace ones, it has always been the case in PHP.
> We're talking about a simple object representing an integer timestamp > and a timezone ID. There is no logical reason those should be hidden - > it's just an implementation detail showing up as an artifact.
There is a reason, or rather reasons, one of them is that internal representation of the data and user-visible one are different. What is inside the object is not what you see on the outside.
> You're describing implementation details - these are features of C, not > features of the PHP language, they happen to leak into the into the PHP > language where they present themselves as inconsistencies.
You can call it whatever name you like, I'm just explaining how it actually works :) Calling everything you don't understand "inconsistencies" seems to be new fashion, but the fact is internal API has more capabilities than user-space API in PHP. It is a deliberate and very old decision stemming from the fact that it is very hard - impossible, really - to give user-space access to engine features safely to PHP code. OTOH, some interesting things only possible if you have access to these features.
> The fact is that DateTime does not behave like a PHP class in terms of > reflection.
It behaves like internal PHP class. You can't really expose state of internal classes via reflection, since in general case this state does not have proper representation in PHP terms besides that very class itself.
-- Stas Malyshev smalyshev@gmail.com

Lester Caine

10 years ago
On 04/06/16 21:23, Stanislav Malyshev wrote:
> In generic case, you can't have internal state of an object, that's why > it's internal. If you need to serialize data, there are > serialize/unserialize handlers for it.
This is also why DateTime is useless for many data handling functions since having to work with 'long hand' for something which is essentially a simple integer value is a heavy overhead. We are stuck with using Timezone management since there is nothing reasonably reliable as an alternative, but we only need timezone to DISPLAY the right text, not manage the raw dates. An alternate date/time variable is essential anyway, which is why some of these discussions are so utterly pointless anyway. date and time are as essential to any system as integer and float but all anybody seems to be bothered about is the same limited subset of 'types' ?
-- Lester Caine - G8HFL ----------------------------- Contact - http://lsces.co.uk/wiki/?page=contact L.S.Caine Electronic Services - http://lsces.co.uk EnquirySolve - http://enquirysolve.com/ Model Engineers Digital Workshop - http://medw.co.uk Rainbow Digital Media - http://rainbowdigitalmedia.co.uk