Viewed   81 times

Consider the following code sample:

$m_oDate = new DateTime('2013-06-12 15:54:25');
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.



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.

Friday, November 11, 2022

The compiler code suggests that this is by design, though I don't know what the official reasoning behind that is. I'm also not sure how much effort it would take to reliably implement this functionality, but there are definitely some limitations in the way that things are currently done.

Though my knowledge of the PHP compiler isn't extensive, I'm going try and illustrate what I believe goes on so that you can see where there is an issue. Your code sample makes a good candidate for this process, so we'll be using that:

class Foo {
    public $path = array(

As you're well aware, this causes a syntax error. This is a result of the PHP grammar, which makes the following relevant definition:

      | T_VARIABLE '=' static_scalar //...

So, when defining the values of variables such as $path, the expected value must match the definition of a static scalar. Unsurprisingly, this is somewhat of a misnomer given that the definition of a static scalar also includes array types whose values are also static scalars:

static_scalar: /* compile-time evaluated scalars */
      | T_ARRAY '(' static_array_pair_list ')' // ...

Let's assume for a second that the grammar was different, and the noted line in the class variable delcaration rule looked something more like the following which would match your code sample (despite breaking otherwise valid assignments):

      | T_VARIABLE '=' T_ARRAY '(' array_pair_list ')' // ...

After recompiling PHP, the sample script would no longer fail with that syntax error. Instead, it would fail with the compile time error "Invalid binding type". Since the code is now valid based on the grammar, this indicates that there actually is something specific in the design of the compiler that's causing trouble. To figure out what that is, let's revert to the original grammar for a moment and imagine that the code sample had a valid assignment of $path = array( 2 );.

Using the grammar as a guide, it's possible to walk through the actions invoked in the compiler code when parsing this code sample. I've left some less important parts out, but the process looks something like this:

// ...
// Begins the class declaration
zend_do_begin_class_declaration(znode, "Foo", znode);
    // Set some modifiers on the current znode...
    // ...
    // Create the array
    // Add the value we specified
    zend_do_add_static_array_element(znode, NULL, 2);
    // Declare the property as a member of the class
    zend_do_declare_property('$path', znode);
// End the class declaration
zend_do_end_class_declaration(znode, "Foo");
// ...
// ...

While the compiler does a lot in these various methods, it's important to note a few things.

  1. A call to zend_do_begin_class_declaration() results in a call to get_next_op(). This means that it adds a new opcode to the current opcode array.
  2. array_init() and zend_do_add_static_array_element() do not generate new opcodes. Instead, the array is immediately created and added to the current class' properties table. Method declarations work in a similar way, via a special case in zend_do_begin_function_declaration().
  3. zend_do_early_binding() consumes the last opcode on the current opcode array, checking for one of the following types before setting it to a NOP:

Note that in the last case, if the opcode type is not one of the expected types, an error is thrown – The "Invalid binding type" error. From this, we can tell that allowing the non-static values to be assigned somehow causes the last opcode to be something other than expected. So, what happens when we use a non-static array with the modified grammar?

Instead of calling array_init(), the compiler prepares the arguments and calls zend_do_init_array(). This in turn calls get_next_op() and adds a new INIT_ARRAY opcode, producing something like the following:

SEND_VAL        '.'
DO_FCALL        'realpath'

Herein lies the root of the problem. By adding these opcodes, zend_do_early_binding() gets an unexpected input and throws an exception. As the process of early binding class and function definitions seems fairly integral to the PHP compilation process, it can't just be ignored (though the DECLARE_CLASS production/consumption is kind of messy). Likewise, it's not practical to try and evaluate these additional opcodes inline (you can't be sure that a given function or class has been resolved yet), so there's no way to avoid generating the opcodes.

A potential solution would be to build a new opcode array that was scoped to the class variable declaration, similar to how method definitions are handled. The problem with doing that is deciding when to evaluate such a run-once sequence. Would it be done when the file containing the class is loaded, when the property is first accessed, or when an object of that type is constructed?

As you've pointed out, other dynamic languages have found a way to handle this scenario, so it's not impossible to make that decision and get it to work. From what I can tell though, doing so in the case of PHP wouldn't be a one-line fix, and the language designers seem to have decided that it wasn't something worth including at this point.

Sunday, August 7, 2022

PHP will very likely implement copy-on-write for its arrays, meaning when you "copy" an array, PHP doesn't do all the work of physically copying the memory until you modify one of the copies and your variables can no longer reference the same internal representation.

Your benchmarking is therefore fundamentally flawed, as your recursiveCopy function doesn't actually copy the object; if it did, you would run out of memory very quickly.

Try this: By assigning to an element of the array you force PHP to actually make a copy. You'll find you run out of memory pretty quickly as none of the copies go out of scope (and aren't garbage collected) until the recursive function reaches its maximum depth.

function recursiveCopy($array, $count) {
    if($count === 1000)

    $foo = $array;
    $foo[9492] = 3; // Force PHP to copy the array
    recursiveCopy($array, $count+1);
Sunday, October 16, 2022
>>> import pandas as pd
>>> date_stngs = ('2008-12-20','2008-12-21','2008-12-22','2008-12-23')
>>> a = pd.Series([pd.to_datetime(date) for date in date_stngs])
>>> a
0    2008-12-20 00:00:00
1    2008-12-21 00:00:00
2    2008-12-22 00:00:00
3    2008-12-23 00:00:00


Use pandas.to_datetime(pd.Series(..)). It's concise and much faster than above code.

>>> pd.to_datetime(pd.Series(date_stngs))
0   2008-12-20 00:00:00
1   2008-12-21 00:00:00
2   2008-12-22 00:00:00
3   2008-12-23 00:00:00
Saturday, November 19, 2022

You need another parameter for specify day - check this:

df = pd.to_datetime(df.yearweek.add('-0'), format='%Y-%W-%w')
print (df)
0   2014-12-07
1   2014-12-14
2   2014-12-21
3   2014-12-28
4   2015-01-18
5   2015-01-25
6   2015-02-01
7   2015-02-08
Name: yearweek, dtype: datetime64[ns]
Sunday, August 21, 2022
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :