10

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?

j0k
  • 22,600
  • 28
  • 79
  • 90
OCDev
  • 2,280
  • 3
  • 26
  • 37

1 Answers1

4

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);
Artefacto
  • 96,375
  • 17
  • 202
  • 225
  • I was able to tool your second solution so that it works from within the parent class, thus answering my question exactly. My parent class creates the property for the child class within the init method as follows: public static function init( $data ) { $calledClass = get_called_class(); $tmp = null; $calledClass::$_data =& $tmp; unset($tmp); static::$_data = $data; } – OCDev Jan 02 '11 at 06:00
  • And actually, I can just do this: public static function init( $data ) { $calledClass = get_called_class(); $calledClass::$_data =& $data; } – OCDev Jan 02 '11 at 06:26
  • As a special note, the parent class must have the property defined in order for this method to work, otherwise, if the Mommy class doesn't have $_data defined as a property, a fatal error is thrown when trying to re-point the child property's reference with $calledClass::$_data =& $data;. (It's because the child class never inherits the pointer from the parent, so it cannot reassign the pointer to anything.) This is in contrast to explicitly defining it in the child class without the workaround in place--it doesn't require it in the parent class when defining it directly in the child class. – OCDev Jan 02 '11 at 07:43