4

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

Community
  • 1
  • 1
kRs
  • 140
  • 7
  • possible duplicate of [do extended classes inherit static var values (PHP)?](http://stackoverflow.com/questions/5059525/do-extended-classes-inherit-static-var-values-php) – scrowler Apr 28 '15 at 23:37
  • 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 Apr 28 '15 at 23:54

3 Answers3

0

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

I wrestled a bear once.
  • 22,983
  • 19
  • 69
  • 116
0

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.

axiac
  • 68,258
  • 9
  • 99
  • 134
  • Thanks for your answer. I will focus on the first part, since self and static are quite clear to me, while what wasn't clear was exactly why modifying static variables in the parent class (inside break_inheritance) would not affect the inherited versions. And most important, **why this only happens with references**, because if, for example, break_inheritance() is changed to self::$my_bar = self:$my_foo , well, it doesn't "break inheritance" any longer. – kRs Apr 29 '15 at 09:53
0

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.

Dharmesh Patel
  • 1,881
  • 1
  • 11
  • 12