In the project my team is currently working on, we're modifying a commercial PHP application. The app is strewn with code where a parent class checks for and works with a property that doesn't exist in the parent class, like so:
class A
{
function doSomething()
{
if (property_exists($this, 'some_property'))
{
$this->some_property = $_REQUEST['val'];
}
}
}
class B extends A
{
protected $some_property;
function doSomething()
{
parent::doSomething();
}
}
We feel vaguely dirty having to modify this code; is this proper design? What are the ways (other than the obvious) something like this can be avoided?
Relying upon methods that must exist in a subclass is not dirty, as long as you can declare them as abstract.
However, it is not good practice to rely on and manipulate properties outside of a class. It's best to use abstract setters, like this:
abstract class A
{
abstract protected function setSomeProperty($data);
public function doSomething()
{
$this->setSomeProperty($_REQUEST['val']);
}
}
class B extends A
{
private $some_property;
public function doSomething()
{
parent::doSomething();
}
protected function setSomeProperty($data)
{
$this->some_property = $data;
}
}
More info here: PHP Class Abstraction
However, since you said you're not allowed to modify the parent class, I would suggest making a subclass that acts as an Adapter to what the parent class "expects", and a class that you're able to design "properly".
You can create a virtual method hook in the parent class which can later be overridden by children.
I think it's more neat to create a sub-class, where all members have function doSomething(). In that case you don't create a not-working function in a parent class (with eventual hacks), but still have the general "super-function".
class A
{
}
class C extends A {
protected $some_property;
function doSomething()
{
$this->some_property = $_REQUEST['val'];
}
}
class B extends C
{
protected $some_property;
function doSomething()
{
parent::doSomething();
}
}
You might consider abstracting the parent class. So the methods that the children must have are declared in the parent, but not implemented.