Ik heb het idee dat sommige OOP'ers behoorlijk vaak interfaces gebruiken.
Stel je hebt meerdere classes die iets kunnen cachen dan lijkt het me zinvol om een interface toe te passen. Echter er zijn ook classes waarvan je bijv. op voorhand weet dat je er maar 1 van nodig hebt.
Stel ik heb bijv. een Config class waar ik configuratie instellingen in op kan slaan. Ik weet dat ik aan 1 (type) class voldoende heb. Ik zal nooit andere varianten van die class maken. Is de conclusie dan ook dat dergelijke classes geen interface nodig hebben? (je gaat ze namelijk nooit uitwisselen met een andere class)
Stel ik heb bijv. een Config class waar ik configuratie instellingen in op kan slaan. Ik weet dat ik aan 1 (type) class voldoende heb. Ik zal nooit andere varianten van die class maken. Is de conclusie dan ook dat dergelijke classes geen interface nodig hebben?
Zeg nooit "nooit". Je kunt er nu van overtuigd zijn dat je iets "nooit" wilt gaan doen, maar je kunt niet in de toekomst kijken. Misschien wil je straks wel een bundel maken die je framework op een server installeert met een aparte MailConfig en een PhpIniConfig.
Het hele eiereneten is dat je wel een API op papier zet. Het schrijven van de interface dwingt je na te denken over hoe je een klasse op de buitenwereld aansluit.
Dat begrijp ik, maar je hebt soms classes waarvan je weet dat je er geen andere van nodig hebt. Ik zal een PhpIniConfig niet zomaar uitwisselen met de default config bijvoorbeeld. En dan nog moet je je afvragen wat het verschil zou zijn tussen beiden.
Ander voorbeeldje dan. Stel ik heb een class waarin ik paths op sla. Daar heb je er maar eentje van nodig. Moet je daar dan een interface voor maken? Wat ik eigenlijk bedoel te zeggen, is dat je dan voor iedere class een interface zou moeten maken. Iedere class zou dan gekoppeld zijn aan een interface. Lijkt me niet de bedoeling?? Of wel????
Dat is uiteraard niet altijd nodig. Maar "naar een interface toe" schrijven dwingt je wel om na te denken over de API. En dat helpt, zelfs als je later in productie de implements ... gewoon weglaat.
Je kunt wel een duidelijke trend zien. Een toenemend aantal PHP-ontwikkelaars gebruikt dezelfde interfaces, ook al kan de achterliggende implementatie verschillen. Dat geldt bijvoorbeeld voor de Logger Interface en de Cache Interface (twee PSR-projecten) en voor de abstractere SPL-interfaces. Met dergelijke standaarden gaan we een gemeenschappelijk taal gaan gebruiken: zó zou PHP-OOP eruit moeten of kunnen zien.
Dus ja, als je een class schrijft die sterk lijkt op iets dat al bestaat in een PSR- of SPL-interface, dan zou ik de lijn helemaal doortrekken en de complete interface implementeren.
Een interface is natuurlijk niet altijd nodig. Alleen zodra je gaat typehinten op een object, of zodra je suggereert dat een object een bepaalde method moet hebben, ga je wel over op typehintent op een interface.
>> Alleen zodra je gaat typehinten op een object ...
Oké, maar nu heb ik bijv. een class die paths opslaat. Daar heb ik er maar eentje van. Als ik die class meegeef aan een de constructor van een ander object, dan kan ik gewoon dit doen toch?
public function __construct(Paths $paths);
Dan typehint ik dus op de class en niet op de interface.
Bij de class-typehint func(Foo $foo) zeg je "is een ... of een child van ..."; bij de interface-typehint func(FooInterface $foo) zeg je meer "gedraagt zich als een ...". Als je vervolgens vooral methoden gebruikt, zou ik hier typehinten op een interface.
Typehinten op de interface is beter schaalbaar. Bijvoorbeeld read(FileCache $entry) is een minder flexibele keuze dan read(CacheInterface $entry).
Natuurlijk kan het ozzie, maar of het goed is... Je bent nu volledig gelimiteerd aan alleen dat Paths object, je hebt nu elke vorm van flexibiliteit uitgesloten voor de parameter die je aan de constructor meegeeft.
>> Typehinten op de interface is beter schaalbaar. Bijvoorbeeld read(FileCache $entry) is een minder flexibele keuze dan read(CacheInterface $entry).
Ja, helemaal mee eens. Maar van een cacher weet je dat er meerdere varianten kunnen bestaan (ook al gebruik ik zelf nog maar 1 variant). Maar in dit geval zou ik dus ook voor Cache(r)Interface kiezen.
>> Je bent nu volledig gelimiteerd aan alleen dat Paths object, je hebt nu elke vorm van flexibiliteit uitgesloten voor de parameter die je aan de constructor meegeeft.
Precies, vandaar ook mijn vraag. Normaal gesproken zou je dat niet willen. Maar een Paths object, daarvan weet je dat je er maar 1 zal hebben. Dan heb ik het gevoel dat het overkill is als je dan een interface gaat implementeren. Snap je?