views:

43

answers:

2

So, I tried to Google this but don't know what this kind of situation is called...

I'm working on my first use of class inheritance, where a parent class defines a set of methods and then several other classes extend that parent.

What I was wondering, is it possible to do something like this:

class foo {
  private bar = false;
  private baz = NULL;
}

Now let's say I have:

class foobar extends foo { }

I'd like to be able to have a condition in "foo" that says if any class extends "foo" and sets "bar = true" then "baz" must be set (ie. not null), or else throw an exception.

Is such a thing possible?

+3  A: 

This seems possible by using a magic setter function that you define in foo, but comes with a serious caveat. Magic getters and setters fire only when you access an inaccessible property.

When operating inside a class, all properties, no matter whether declared private, public or protected, are usually accessible, so the magic getter and setter functions will not fire. There is only one exception: Properties that were declared private in an ancestor class. Those will be hidden (inaccessible) to descendant classes, and the magic functions will fire.

This means that you will need to declare bar and baz in foo. It wouldn't work if you would declare them in foobar, because they would become accessible.

With this in mind, the following will work as you want:

class foo {
  private $bar = false;
  private $baz = NULL;

  public function __set($name, $value)
   {
     if ($name == "bar") 
      { if ($value == true)
         {
           if ($this->baz == null) 
            throw new Exception();
         }
      }
   } 
}

class foobar extends foo {

     function test()
      {
       $this->bar = "TEST";   
      }

 }


 $foobar = new foobar();
 $foobar->test();  // Will throw an exception

If you want to read bar and baz from within foobar, you will also need to define a magic getter function.

Pekka
That is phenomenal. Thanks!
Andrew
@Andrew You're welcome. I'm somewhat surprised myself that this is possible :) Having to declare properties private in an ancestor to have getters and setters fire seems somewhat arbitrary, but I tested it and it seems to work fine.
Pekka
A: 

Just run a construct function in the second class.

class foo {
  private bar = false;
  private baz = NULL;
  public function __construct() {
    if ($this->bar && is_null($this->baz)) // throw exception
  }
}
class foobar extends foo {
  public function __construct($baz) {
    $this->baz = $baz;
    $this->bar = true;
    parent::__construct(); // Now run the parent's constructor
  }
}

Many different ways to do it...

animuson
Yes, but the real reason I want to do this is I think that *I* may not be the person who writes the "foobar" class. So, if someone tries to use a certain functionality from the parent (bar = true) then they must also provide some information (baz != null). Since my concern is to catch an incomplete extension of the parent class I wouldn't want the implementation to be dependent on any code inside the child class.
Andrew