Question

Consider the following code sample:

$m_oDate = new DateTime('2013-06-12 15:54:25');
print_r($m_oDate);
echo $m_oDate->date;

Since PHP 5.3, this produces (something like) the following output:

DateTime Object
(
    [date] => 2013-06-12 15:54:25
    [timezone_type] => 3
    [timezone] => Europe/Amsterdam
)
2013-06-12 15:54:25

However the following code:

$m_oDate = new DateTime('2013-06-12 15:54:25');
echo $m_oDate->date;

...simply emits an error:

Notice: Undefined property: DateTime::$date in ...

Why does print_r() "add" these properties to the object? Note that they are not defined as part of the DateTime class on the manual page.

Était-ce utile?

La solution 2

There is some magic occurring but it's pretty simple.

The class DateTime doesn't have a public variable 'date' that you're meant to access. However, as a side effect of how PHP works, there is a variable created when you call print_r or var_dump on that class.

After that magic happens 'date' is available, but it shouldn't be. You should just use the getTimestamp function to make your code work reliably.

Autres conseils

This has been reported as Bug #49382 in PHP.

In PHP 5.3, internal functionality was added to allow print_r() to show details of the underlying timestamp value held by an instance of DateTime, to assist with debugging. A side effect of this change is that when the object is dumped to text, these phantom public properties are added to the instance.

The same effect can be achieved by using reflection to access these properties, and if you need to access the properties then using reflection would be the way to go, so you don't provoke the error.

However, it should be noted that you shouldn't really use these properties - since they are not defined as members of the object, there is no guarantee they will continue to carry the same data (or even exist) in future PHP versions. If you need to access the information, use the following methods, defined as part of the API, instead:

// $obj->date
$obj->format('Y-m-d H:i:s');

// $obj->timezone
$obj->getTimezone()->getName();
// or...
$obj->getTimezone()->getOffset();
// or...
$obj->getTimezone()->listAbbreviations(); // returns an array, so may need 
                                          // further processing to be of use

NB: The timezone_type property is not accessible through the PHP API. It is an internal value and not useful in userland, because it describes the type of string that timezone holds when the object is dumped - i.e. one of the three methods for obtaining timezone information in the code sample above. For completeness, its possible values are defined in the following way:

Value | Type                  | Userland equivalent
------+-----------------------+----------------------------------
  1   | time offset           | DateTimeZone::getOffset()
  2   | TimeZone abbreviation | DateTimeZone::listAbbreviations()
  3   | TimeZone identifier   | DateTimeZone::getName()

There's no date property in DateTime; that's why you're getting (Undefined property: DateTime::$date).

print_r() performs some introspection on the object to display its contents; this causes the object to magically create the ::date property. This is not documented though, so using this may break your code in the future.

You need something like $m_oDate->format('m-d-Y'); instead.

The problem lies here:

static HashTable *date_object_get_properties(zval *object TSRMLS_DC)
{
    // ...
    zend_hash_update(props, "date", 5, &zv, sizeof(zval), NULL);
    // ...

The function date_object_get_properties is called when any data dumping is made (print_r, var_dump, var_export). The hash table is updated for data representing, unfortunately this is made public.

Consider the following code-example:

$m_oDate = new DateTime('2013-06-12 15:54:25');
some_func($m_oDate);
echo $m_oDate->{'ROXXOR_IS_BACK!!'};

The most obvious difference to yours is that instead of the print_r function a different one some_func is called. The expectations might differ because you know print_r but you don't know some_func but that is only to sharpen your senses. Let's wait a moment until I show the definition of that function.

The second difference is the name of the property that is getting echoed. Here I've choosen a name that is really exceptional: {'ROXXOR_IS_BACK!!'}, again to sharpen your senses.

This name is that crazy that is must be obvious not being part of DateTime albeit when the example above is executed, it's totally clear that this roxxor property must exists. Program Output:

PHP never lets you down.

So how come? Yes, you sure already have an idea how that works. The some_func() function must have added it. So let's take a look into the functions definition:

function some_func($m_oDate) {
    $m_oDate->{'ROXXOR_IS_BACK!!'} = 'PHP never lets you down.';
}

Yes, it's now clearly visible that this function has added a property to the object. And it also shows that this is totally easily possible with any object in PHP.

Compare with an array in PHP, you can also add new keys when you want to.

This example has not been chosen out of nothing, because this is where objects in PHP come from: They are just syntactic sugar around arrays and this has to with the time when objects in PHP were introduced back in PHP 3:

At the time classes were introduced to the source tree of what was to become PHP 3.0, they were added as syntactic sugar for accessing collections. PHP already had the notion of associative array collections, and the new critters were nothing but a neat new way of accessing them. However, as time has shown, this new syntax proved to have a much more far-reaching effect on PHP than was originally intended.

-- Zeev Suraski about the standard object since PHP 3 (archived copy) - via Why return object instead of array?

This is also the simple explanation why it's totally common in PHP that functions can add member variables which have not been defined earlier in the class. Those are always public.

So when you do assumptions about some object having a property or not, take a look where it comes from. It must not be part of the class but might have been added later.

And keep the following in mind:

Do not use print_r and var_dump in production code.

For the fun of it, this is how you can make it work, using Reflection:

$m_oDate = new DateTime('NOW');
$o = new ReflectionObject($m_oDate);
$p = $o->getProperty('date');
echo $p->getValue($m_oDate);

Source

You should use DateTime::format or DateTimeImmutable::format as the case may be instead

$m_oDate = new DateTime('NOW');
echo $m_oDate->format("r");
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top