Stel ik maak een algemene class om data in op te slaan. Vervolgens wil ik ook een class maken om configuratiegegevens in op te slaan. Daar kan ik eigenlijk perfect de algemene Data class voor gebruiken.
Nu vraag ik me iets vreemds af. Wat is nu wijsheid. Om voor de configuratie gebruik te maken van de algemene data class? Dus:
<?php
$config_settings = new Data();
?>
Of is het slimmer om toch een aparte Config class te maken die de Data class extend?
<?php
class Config extends Data {
}
$config = new Config();
?>
Nu hebben we wel een aparte Config class, maar deze is wel leeg. Er staan geen methods is. Wat zou jullie voorkeur hebben?
Elke klasse een eigen interface geven, is meestal geen goed idee. Ik denk dat je beter af bent door het hogerop in de hiërarchie te formaliseren, bijvoorbeeld:
- class PathsCollection extends DataCollection
- abstract class DataCollection implements ArrayAccess, Countable, Serializable
Als je objecten wilt cachen, komt de Serializable interface van pas. Dat is natuurlijk ook een keuze, zoals alles, maar ik noemde het voorbeeld omdat deze ontwerpbeslissing eerder thuishoort op het niveau DataCollection dan op het niveau PathsCollection extends DataCollection.
Wat is "verkeerde inhoud"? Als je bijvoorbeeld een ongewenst datatype of een ongeldige datastructuur bedoelt, dan is het antwoord volmondig: ja, je kunt nooit te veel typehinten, wel te weinig.
Je hebt een object Foo en dat object heeft een object met Paden nodig. We hadden net vastgesteld dat PathsCollection en DataCollection is, en DataCollection implement een DataCollectionInterface. PathsCollection implement (via DataCollection) dus ook een DataCollectionInterface.
Goed, we hebben in class Foo dus een PathsCollection nodig. Die kan ik als volgt typehinten:
<?php
Class Foo {
public function __construct(DataCollectionInterface $paths) {
}
}
?>
Wat we nu dus in feite zeggen, is dat we een object willen wat voldoet aan de DataCollectionInterface. Echter, in plaats van een PathsCollection, zou ik dus ook een ConfigCollection, RoutesCollection of FooBarCollection kunnen meegeven. Is dat gebruikelijk? Of a) moet niet naar een interface maar naar een class (PathsCollection) typehinten, of b) moet ik wellicht een nieuwe PathsCollectionInterface maken, en daar naar typehinten?
Dos, hoe jij het omschrijft is inderdaad precies zoals ik het bedoelde bij optie b.
Maar is dit ook de bedoeling van het gebruik van interfaces? Moet een interface daar tegen "beschermen"? Dus in dit specifieke voorbeeld, moet een interface er voor waken dat ik alleen paden kan ingeven (en niet bijv. routes of configuratiesettings). Is dat waar een interface voor dient?
Je ontkomt er dan niet aan te typehinten op de klasse. Eén klasse kan namelijk wel verschillende interfaces implementeren, maar je kunt niet typehinten met meerdere interfaces tegelijk.
Als je naast een PathsCollection nog een ConfigCollection en een RoutesCollection hebt, dan zou ik $paths wel concreet typehinten met PathsCollection $paths, niet met het ruimere DataCollectionInterface $paths. De klasse implementeert de interface (direct): je kunt dat niet meer elegant ombuigen als je dat (indirect) met de typehint op de interface doet in Foo.