Ik ben in aanraking gekomen met Generics via het Microsoft.Net framework, maar maar met een beetje geluk gaat PHP ook Generics ondersteunen.
Generics?
Wat zijn Generics dan eigenlijk? Zoals ik wel eens op kantoor laat vallen, zijn Generics de oplossing voor alle problemen. Een collega had laatst een opmerking die misschien beter past bij Generics, maar ik kan de context wel iets uit verband hebben getrokken:
Een generieke implementatie die specifiek wordt aangeroepen
Met Generics kun je de types binnen een scope laten bepalen door de aanroepende code. Je stelt de keuze van een type uit tot het moment dat de code wordt aangeroepen. Generics maken het mogelijk om classes en functions te maken die met elk type kunnen omgaan.
Dat kan ik al!
Zeker in dynamisch getypeerde talen zoals PHP, maar ook in meer statisch getypeerde talen, kun je dit natuurlijk al. In PHP hoef je bijvoorbeeld helemaal niet op te geven welk type een bepaalde parameter heeft. Je stopt erin wat je wilt en verder niet zeuren.
Maar wat gebeurt er als je de ene keer een object van type X gebruikt en daarna een object van type Y? Begrijpt je code dat dan nog wel? Verwacht de code niet een bepaald type? Het is in ieder geval niet wat je wilt en levert lastige bugs op.
Voorbeelden
Voorbeelden zeggen vaak meer dan niet-voorbeelden; theorie is ook maar zo theoretisch. Het eenvoudigste en misschien wel duidelijkste voorbeeld heeft te maken met collecties of lijsten. Laten we zeggen dat we een List class hebben, daar wat aan toevoegen en vervolgens iets met de elementen willen doen.
$myAwesomeList = new List();
$myAwesomeList->add(3); // add an integer
$myAwesomeList->add(new Amount(5, 2)); // add an Amount object with value 5 and precision 2
$myAwesomeList->add('my awesome text here'); // add a string
$total = 0;
// or should we have:
// $total = new Amount(0, 2);
foreach ($myAwesomeList->getItems() as $item) {
$total += $item; // what would happen here?
// we could have wanted this for Amount:
// $total = $total->add($item);
// and for strings maybe:
// $total .= $item;
}
Ik denk dat je wel begrijpt wat ik bedoel, maar hoe kunnen we onze intentie nu beter vastleggen?
$myAmountList = new List<Amount>();
$myAmountList->add(new Amount(5, 2); // this is ok
// this is not ok:
// $myAmountList->add(3);
// $myAmountList->add('your awesome text here');
$total = new Amount(0, 2);
foreach ($myAmountList->getItems() as $item) {
$total = $total->add($item);
}
// but you could use the generic List class for strings as well:
$myStringList = new List<string>();
$myStringList->add('this works splendidly');
Hoe definieer je deze class dan? Ik zal je niet langer in spanning houden.
// T is the Type parameter
class List<T>
{
private $items = [];
public function add(T $item)
{
$this->items[] = $item;
}
}
Je kunt een stapje verder gaan door een collectie te maken van Key/Value paren.
// Type parameters for Key (K) and Value (V)
class KeyValuePair<K, V>
{
private $key; // of type K
private $value; // of type V
public function __contstruct(K $key, V $value)
{
$this->key = $key;
$this->value = $value;
}
}
class KeyValueCollection<K, V>
{
private $items = [];
public function add(KeyValuePair<K, V> $pair)
{
$this->items[] = $pair;
}
public function addKeyWithValue(K $key, V $value)
{
$this->items[] = new KeyValuePair<K, V>($key, $value);
}
}
In talen als Java en C# heb je nog wel een voordeel die er in PHP niet zal zijn: tijdens het compileren krijg je de fouten van het verkeerd gebruik van types, zoals een Amount in de $myStringList. In PHP zal dit (zoals zo veel fouten) pas runtime gecheckt worden.
Is dat alles?
Nee, er is nog veel meer. Ik kan niet alles over Generics kwijt in een blog en ik weet zelf ook niet alles, zeker niet als het gaat om de specifieke implementatie in PHP. Ik wil hier alleen een tipje van de sluier oplichten en je interesse wekken om je ogen open te houden voor Generics.
Wil je meer weten, check dan deze links of google zelf.