Interfaces er godt hvis du er igang med et projekt hvor der er flere udviklere tilknyttet (ligeledes abstrakte klasser, men det bør give sig selv herefter).
For at noget kan blive rigtigt OOP, og ikke bare filer med klasser i, bør du anvende de muligheder der er for nedarvning og polymorfi.
Eksempelvis kunne man forestille sig at du skulle lave en slags bilportal.
Til den bilportal vil du anvende nogle klasser (objekter) til at præsentere bildata. Men da du ikke er den eneste udvikler på bilportalen, er det vigtigt at I bliver enige om hvad et objekt skal indeholde for at outputtet kan blive ensartet.
Her kan man lave et interface:
interface Biler
{
public function getYear( $model );
public function getPrice( $model );
public function getModels();
public function getImages( $model );
public function getAdditionalInfo( $model );
}
Super, nu ved jeg som udvikler at jeg skal implementere ovenstående interface og hvis jeg ikke har de funktioner med som er beskrevet ovenfor, vil mit objekt ikke virke.
Jeg kan således lave forskellige objekter og være sikker på at ovenstående funktioner vil være en del af mit objekt - og det gælder alle udviklere.
Eksempelvis vil udvikler nummer 1 måske gøre således:
class Seat_Ibiza implements Biler
{
public function getYear( $model )
{
$db->queryItem("SELECT year FROM tCars WHERE model = '$model'");
return $db->result->year;
}
public function getPrice( $model );
{
$db->queryItem("SELECT price FROM tCars WHERE model = '$model'");
return $db->result->year;
};
public function getModels()
{
$sql = "SELECT model FROM tCarModels WHERE carType = 'SEAT' ORDER BY model ASC";
$db->query($sql);
return $db->result->result2array();
};
public function getImages( $model )
{
$sql = "SELECT filename, filecaption FROM tCarImages WHERE modelType = '$model' ORDER BY filename ASC";
$db->query($sql);
return $db->result->result2array();
};
public function getAdditionalInfo( $model )
{
$db->queryItem("SELECT additionalInfo FROM tCars WHERE model = '$model'");
return $db->result->additionalInfo;
};
}
mens udvikler nummer 2 mener at nedenstående er smartere:
class Peugeot_406 implements Biler
{
private $models = array();
private $years = array();
private $prices = array();
private $images = array();
private $info = array();
public function __construct()
{
$this->_populateModels();
$this->_populateYears();
$this->_populatePrices();
$this->_populateImages();
$this->_populateInfo();
}
public function getYear( $model )
{
return $this->years[$model];
};
public function getPrice( $model );
{
return $this->prices[$model];
};
public function getModels()
{
return $this->models;
};
public function getImages( $model )
{
return $this->images[$model];
};
public function getAdditionalInfo( $model )
{
return $this->info[$model];
};
private function _populateModels()
{
$sql = "SELECT model FROM tCarModels WHERE carType = 'SEAT' ORDER BY model ASC";
$db->query($sql);
$this->models = $db->result->result2array();
};
private function _populateYears()
{
foreach($this->models as $model)
{
$db->queryItem("SELECT year FROM tCars WHERE model = '$model'");
$this->years[$model] = $db->result->year;
}
};
private function _populatePrices()
{
foreach($this->models as $model)
{
$db->queryItem("SELECT price FROM tCars WHERE model = '$model'");
$this->prices[$model] = $db->result->price;
}
};
private function _populateImages()
{
foreach($this->models as $model)
{
$sql = "SELECT filename, filecaption FROM tCarImages WHERE modelType = '$model' ORDER BY filename ASC";
$db->query($sql);
$this->images[$model] = return $db->result->result2array();
}
};
private function_populateInfo()
{
foreach($this->models as $model)
{
$db->queryItem("SELECT additionalInfo FROM tCars WHERE model = '$model'");
$this->info[$model] = $db->result->additionalInfo;
}
};
}
Nu ved jeg så at uanset hvilken type bil jeg skal hente info om vil alle oplysningerne altid være tilgængelige på den samme måde, uanset måden klassen er lavet på:
$bil = $_POST["bil"];
if( !class_exists($bil) )
{
header("Location: notfound.php");
exit;
}
$bilObj = new $bil();
$modeller = $bilObj->getModels();
...
På den måde har du både brugt interfaces og polymorfi.
En abstrakt klasse kan bruges på nogenlunde samme måde.
Men vi tager udgangspunkt i det førnævnte; vi har bare behov for at at tilføje standard funktionalitet til vores bil objekter:
abstract class Biler
{
protected $db; // vores database abstraktionslag kan tilgås gennem denne
protected function __construct()
{
$this->_startMysqlConnection();
}
private function _startMysqlConnection()
{
$this->db = new MysqlObj("localhost", "brugernavn", "kodeord", "database");
}
abstract public function getYear( $model );
abstract public function getPrice( $model );
abstract public function getModels();
abstract public function getImages( $model );
abstract public function getAdditionalInfo( $model );
}
Og istedet for at implementere interfacet fra før, extender vi nu blot vores klasser:
Udvikler nr 1
class Seat_Ibiza implements Biler
{
public function getYear( $model )
{
$db->queryItem("SELECT year FROM tCars WHERE model = '$model'");
return $db->result->year;
}
...
Udvikler nr 2:
class Peugeot_406 extends Biler
{
private $models = array();
private $years = array();
private $prices = array();
private $images = array();
private $info = array();
public function __construct()
{
parent::__construct();
$this->_populateModels();
$this->_populateYears();
$this->_populatePrices();
$this->_populateImages();
$this->_populateInfo();
}
...
Jeg håber det gav lidt mere mening...