phpoopphp-5.3late-static-binding

PHP 5.3: Late static binding doesn't work for properties when defined in parent class while missing in child class


Take a look at this example, and notice the outputs indicated.

<?php

class Mommy
{
    protected static $_data = "Mommy Data";

    public static function init( $data )
    {
        static::$_data = $data;
    }

    public static function showData()
    {
        echo static::$_data . "<br>";
    }
}

class Brother extends Mommy
{
}

class Sister extends Mommy
{
}

Brother::init( "Brother Data" );
Sister::init( "Sister Data" );

Brother::showData(); // Outputs: Sister Data
Sister::showData(); // Outputs: Sister Data

?>

My understanding was that using the static keyword would refer to the child class, but apparently it magically applies to the parent class whenever it is missing from the child class. (This is kind of a dangerous behavior for PHP, more on that explained below.)

I have the following two things in mind for why I want to do this:

  1. I don't want the redundancy of defining all of the properties in all of the child classes.
  2. I want properties to be defined as defaults in the parent class and I want the child class definition to be able to override these properties wherever needed. The child class needs to exclude properties whenever the defaults are intended, which is why I don't define the properties in the child classes in the above example.

However, if we are wanting to override a property at runtime (via the init method), it will override it for the parent class! From that point forward, child classes initialized earlier (as in the case of Brother) unexpectedly change on you.

Apparently this is a result of child classes not having their own copy of the static property whenever it isn't explicitly defined inside of the child class--but instead of throwing an error it switches behavior of static to access the parent. Therefore, is there some way that the parent class could dynamically create a property that belongs to the child class without it appearing inside of the child class definition? That way the child class could have its own copy of the static property and the static keyword can refer to it properly, and it can be written to take into account parent property defaults.

Or is there some other solution, good, bad, or ugly?


Solution

  • It does refer to the correct class, it's just that, unless redeclared or otherwise the reference set is broken, static properties in subclasses are in the same reference set as in the superclass.

    So you must do:

    class Brother extends Mommy
    {
        protected static $_data;
    }
    

    or:

    class Brother extends Mommy
    {
    }
    
    $tmp = null;
    Brother::$_data =& $tmp;
    unset($tmp);