3
abstract class Mother {
        protected static $foo = null;
        protected static $bar = null;

        public function getFoo() { return static::$foo; }
        public function getBar() { return static::$bar; }
        public function setFoo($foo) { static::$foo = $foo; }
        public function setBar($bar) { static::$bar = $bar; }
}

class Brother extends Mother {
        protected static $foo = 'BROTHERS';
}

class Sister extends Mother {
        protected static $foo = 'SISTERS';
}

$brother1 = new Brother();
$brother2 = new Brother();
$sister1 = new Sister();
$sister2 = new Sister();

$sister1->setBar('ONLY SISTERS'); // We set $bar = 'ONLY SISTERS' at sister1.
// We want only Sister instances to get this value...
// however Brother instances also get this value!

    echo '<p>Brother 1: Foo="'.$brother1->getFoo().'", Bar="'.$brother1->getBar().'"</p>';
// Foo="BROTHERS", Bar="ONLY SISTERS"
    echo '<p>Brother 2: Foo="'.$brother2->getFoo().'", Bar="'.$brother2->getBar().'"</p>';
// Foo="BROTHERS", Bar="ONLY SISTERS"
    echo '<p>Sister 1: Foo="'.$sister1->getFoo().'", Bar="'.$sister1->getBar().'"</p>';
// Foo="SISTERS", Bar="ONLY SISTERS"
    echo '<p>Sister 2: Foo="'.$sister2->getFoo().'", Bar="'.$sister2->getBar().'"</p>';
// Foo="SISTERS", Bar="ONLY SISTERS"

So apparently if static::$bar is not explicitly redefined in every child (Brother, Sister) their parent (Mother) will set the value for them (or at least for those who did not redefine it).

The question: Is there any way to prevent children who did not redefine static::$bar from receiving the new value? In other words, how to make sure only the referred class gets a new value, EVEN if static::$bar is not explicitly redefined in every child?

miken32
  • 42,008
  • 16
  • 111
  • 154
mae
  • 14,947
  • 8
  • 32
  • 47
  • 1
    I see only one option to achieve this. You have to overwrite the getBar and setBar methods in the sister class. The setBar method writes to $this->bar and the getBar checks if $this->bar is set and retrieves from parent::$bar otherwise. – Dan Mar 02 '12 at 20:26
  • Is there a reason to have these static when you have an object instance? – D_C Mar 02 '12 at 20:28
  • @Dan You are probably right. Another option is to re-declare static::$bar in every child. The problem is there is no way to force the programmer to do this. – mae Mar 02 '12 at 20:42
  • @DaveC Each object will have the same value, so having a copy of it in each instance seems wasteful. – mae Mar 02 '12 at 20:46
  • The whole purpose of static variables (and associated values) is to persist across instantiations. – Mike Purcell Mar 02 '12 at 21:07
  • @user1132363: I see where you're coming from. Is this for a framework you are planning and you are afraid your team members will not follow the guidelines or are you expecting a third party to interfere with the framework? – Dan Mar 03 '12 at 19:53

2 Answers2

2

No, not the way you're doing it. That's what private scope is for. Child classes inherit all public and protected static properties--which mean they all point to the same value whether they are a parent, child, or sibling.

This is correct and good OO.

You should define the variable it as private static in the parent class and then the child wouldn't be able to see it directly and could create their own private static variable with the same name if needed.

Provide static getters and setters in your class to access the private static property.

Brother::getFoo();
Sister::getFoo();

You can make the getFoo() in the parent class Mother abstract or not, if you need to access it directly make it non-abstract so you can do:

Mother::getFoo();
Ray
  • 40,256
  • 21
  • 101
  • 138
  • Alright I think this is the right direction, but I need some more detail on how (and where) exactly to implement these functions, especially the $bar getter/setter, because I keep getting this error for anything I try: _Fatal error: Cannot access property Sister::$bar_ – mae Mar 02 '12 at 21:13
  • 1
    Should I provide static getters/setters in **every** child class? – mae Mar 02 '12 at 22:39
  • You can create one in the Mother class, and it will access the Mother::$bar with Mother::getBar(). Yes, you'll need to implement getters and setters for all classes, since $bar is private to Mother. – Ray Mar 03 '12 at 03:46
  • 1
    That's useless. It just creates pointless work for the programmer. – mae Mar 05 '12 at 15:31
1

This is just madness.

You should understand that extend defines IS A relationship. For example : class Duck extends Bird{} this means that every instance of Duck is a Bird.

So in your example, every Brother is a Mother. I fail to see how this would make a sense.


And the other thing : why the hell are you abusing static variables? What you are doing there is not object oriented programming. You are just wrapping global scope variables and functions in a namespace ( which happens to look like class ).

Some additional links on the subject, you might find useful:

Community
  • 1
  • 1
tereško
  • 58,060
  • 25
  • 98
  • 150
  • 1
    So you think that it's better to have a copy of the same string in every subclass? – mae Mar 05 '12 at 15:32
  • @user1132363, what ? Where did i say that? Maybe you should learn about dependency injection. – tereško Mar 05 '12 at 15:47
  • 2
    Well you are clearly implying that I should not be using static variables. At least not the way I am doing it now - but you did not provide any alternative solution. – mae Mar 05 '12 at 15:57
  • If you need one change to affect multiple instances of an object, then it is some external state. Which means, that all the objects contain an instance which is shared between them. Learn about dependency injection and stop asking for code in silver plate. – tereško Mar 05 '12 at 16:03
  • 1
    +1 Somewhere, a single tear just rolled down [**Barbara Liskov's**](http://en.wikipedia.org/wiki/Barbara_Liskov) cheek. –  Mar 05 '12 at 16:13