The reason why I'm using interfaces and abstract classes is because I may need to derive an abstract class from multiple interfaces and extend another class as an abstract class that is the basis for more extension. I can't have a class extend two classes but I can have it implement more than one interface. On the same principle I may need to derive a class from an abstract class (with all it's class data members) and also from another interface that is unrelated. So while I do agree with you that functionally interfaces and abstract classes are more or less the same, language wise I can't extend 3 abstract classes like I can implement 3 interfaces. Likewise if I implement everything as interfaces, then I cannot have a class data member propagate down the inheritance tree-I'll need to redeclare the data member every time which doesn't work too well with static variables and I cannot define method bodies like I can in abstract classes. An example of this would be:
<?php
interface obj
{
abstract public function hi();
public $hi; //does not work-generates Parse error
public function doSomething() //does not work-generates Parse error
{
//do something
}
}
interface cacheable
{
abstract public function cache();
}
abstract class deadObj extends statVar, formVar //does not work-generates Parse error
{
//class body
}
class normalObj implements obj
{
public function hi()
{
return "I'm a normal object without anything extra than the obj interface";
}
}
abstract class cacheableObj implements obj, cacheable
{
protected static $cacheableobjCount=0; //this inherited class member would not function the way I want it to if I implemented it individually-I want to count all cacheableObj created in entire script execution
public function _construct()
{
cacheableObj::$cacheableobjCount++;
}
abstract public function toString();
}
class underivedStatVar implements obj, cacheable //if no intermediary abstract class
{
private $str;
public function hi()
{
return "I am a stat object";
}
public function cache()
{
//do something
}
public function toString()
{
return "statVar: " . $this->str;
}
}
class underivedFormVar implements obj, cacheable //if no intermediary abstract class
{
private $get;
public function hi()
{
return "I am a form object";
}
public function cache()
{
//do something
}
public function toString()
{
return "formVar: " . $this->get;
}
}
class statVar extends cacheableObj
{
private $str;
public function hi()
{
return "I am a stat object";
}
public function cache()
{
//do something
}
public function toString()
{
return "statVar: " . $this->str;
}
}
class formVar extends cacheableObj
{
private $get;
public function hi()
{
return "I am a form object";
}
public function cache()
{
//do something
}
public function toString()
{
return "formVar: " . $this->get;
}
}
//now say I want a function that calls toString() for formVar and statVar
function bar(cacheableObj $obj)
{
echo $obj->toString(); //this works the way it should
}
//now say I want a function that calls toString() for both underivedStatVar and underivedFormVar without cacheableObj
function bar2(obj $obj) //obj doesn't support toString(), so technically can't use
{
//it works (dynamic typing), but it seems like bad programming practice since we did all the type hinting
//also what would stop me from passing a normalObj object? it satisfies the obj requirement
echo $obj->toString();
}
?> |
It's a rather long example but I hope it shows where I'm coming from
David