4
votes

I don't understand why, in the code below, $my_foo and $my_bar are correctly inherited by the child class, but if I change $my_foo by assigning a reference to $my_var, the child class still sees the original value..

  <?php
    class Foo
    {
        public static $my_foo = 'foo';
        public static $my_bar = 'bar';

        public static function break_inheritance() {
            self::$my_bar = &self::$my_foo;
        }

        public static function foo_print_vars() {
            print self::$my_foo." ";
            print self::$my_bar."\n";
        }
    }

    class Bar extends Foo
    {
        public static function bar_print_vars() {
            print self::$my_foo." ";
            print self::$my_bar."\n";
        }
    }


    Bar::bar_print_vars(); // OUTPUTS foo bar
    Foo::break_inheritance(); 
    Foo::foo_print_vars(); // OUTPUTS foo foo
    Bar::bar_print_vars(); // OUTPUTS foo bar

EDIT: this is a similar question: do extended classes inherit static var values (PHP)? but mine is more focused on inheritance and references.

EDIT2: please note that the point of this question is not about late static binding, but it's why, since $my_foo and $my_bar are inherited, changing them in Foo doesn't affect them when accessed in Bar. And this only happens with references. In fact if we change:

 public static function break_inheritance() {
            self::$my_bar = self::$my_foo; // removed reference in assignment
        }

the behavior totally changes and the last Bar::bar_print_vars(); // OUTPUTS foo foo

3
Hi @scrowler, I had seen such question and although such question is more generic (user only asks about inheritance of static properties), the answer considers my case as an example. However, I didn't find a clear explanation on what causes this behavior with references, and I decided to ask a question expressly about it. - kRs

3 Answers

0
votes

Foo is a different class than Bar. Try calling Bar::break_inheritance(); and see what happens.

0
votes

Think about static properties of a class as global variables with fancy names.

class Foo
{
    public static $my_foo = 'foo';
    public static $my_bar = 'bar';
    // ...
}

The code above declares two static properties of class Foo whose full names are Foo::$my_foo and Foo::$my_bar.

By extending Foo, class Bar produces two more static properties named Bar::$my_foo and Bar::$my_bar.

The code:

class Foo
{
    public static function break_inheritance() {
        self::$my_bar = &self::$my_foo;
    }
}
Foo::break_inheritance(); 

modifies Foo::$my_bar. It does not affect Bar::$my_bar.

If you call it as:

Bar::break_inheritance(); 

it still changes Foo::$my_bar and does not affect Bar::$my_bar.

A reference that uses self:: is bound on compilation to the property of the class where it is used. It is the same as you write Foo::$my_bar = &Foo::$my_foo;. No matter how you call the method break_inheritance(), it will always modify Foo::$my_bar.

If you want to use method break_inheritance() to change Bar::$my_bar you have to change it to use static:: instead of self:::

class Foo
{
    public static function break_inheritance() {
        static::$my_bar = &static::$my_foo;
    }
}
Foo::break_inheritance();         // Changes `Foo::$my_bar`
Bar::break_inheritance();         // Changes `Bar::$my_bar`

This is called late static binding and was introduced in PHP 5.3.

Late static binding (static::) works for class properties and methods the same way $this-> works for regular properties and methods. It uses the property or the method defined in the class where you use it (in the child class), if any, and not the property or method inherited from the parent class.

0
votes

This is due to the new feature introduced in PHP version 5.3.0 called Late static binding.

Late static binding comes from the fact that static:: will not be resolved using the class where the method is defined but it will rather be computed using runtime information.