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
Die ArrayAccess gebruik ik niet. Ik wil juist van een array een object maken, niet andersom :)

Ik heb nu voor de DataCollection wel een interface gemaakt, die Countable en IteratorAggregate extendt.

Waar is die Serializable goed voor?
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.
Nou wat ik eigenlijk bedoel is meer dit:

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?
Dan klinkt b beter. Het is specifieker en toch kan het met een object werken dat DataCollection niet extend, wat weer handig kan zijn voor unit tests.

interface PathsCollectionInterface extends DataCollectionInterface {}

class PathsCollection extends DataCollection implements PathsCollectionInterface { ... }
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.

En de andere oplossing, om een aparte PathsCollectionInterface te maken (zie hierboven het voorbeeld van Dos)?

Reageren