Een Processor/Core/Kernel class doorloopt allerlei stappen. Mag de consructor deze stappen triggeren/uitvoeren? Even een heeeeel erg versimpeld voorbeeldje met 3 fictieve functies.
<?php
class Processor {
private $request;
public function __constructor($request) {
$this->request = $request.
$this->initializeRequest();
$this->executeRequest();
$this->sendResponse();
}
}
?>
Zou de constructor deze functies mogen triggeren? Is dat oké volgens het OOP principe?
Als je zoals in je eerste voorbeeld laat zien een class hebt die maar 1 public methode heeft, in dit geval het afhandelen van een request, en je weet 100% zeker dat er geen extra methodes of dependencies bij komen kun je er ook een static methode van maken. e.g.
Processor::execute($request);
Puur gezien vanuit readability van de code vind ik dat beter dan
new Processor($request);
Maar uiteindelijk is het natuurlijk je eigen keuze :)
Verder ben ik het er ook mee eens dat de constructor alleen maar gebruikt moet worden voor het initialiseren van het object, en eventueel valideren van de binnenkomende variablen. Stel je voor dat je Processor::execute methode een fout geeft bij het versturen van een response ($this->sendResponse()), en het enige dat ik, als externe developer die met jou code werkt, heb gedaan is een nieuw Processor object aanmaken zou ik wel even raar opkijken.
>> Als je altijd in twee stappen dit moet doen voordat je een bruikbare $foo hebt, dan deugt het ontwerp van de klasse niet:
Hier heb ik nog een vraagje over.
Stel dat je de Processor class hebt en het enige wat je in de constructor doet is het request setten, en verder niks. In principe is de class zelf nu dus gebruiksklaar.
Nu is de volgende stap in het proces dat je een aantal dingen wilt initialiseren, je wilt bijv. de services laden en je wilt wat gegevens inladen (bijv. paden). In feite is dit dus ook een vorm van initialiseren. Hoort dit dan ook thuis in de constructor?
@NOLot:
>> ... en je weet 100% zeker dat er geen extra methodes of dependencies bij komen kun je er ook een static methode van maken. e.g.
Waarom dan een statische methode en niet dit:
<?php
$processor = new Processor($request);
$processor->execute();
?>
Wat is precies het verschil?
Bij een statische methode afhankelijk ben je afhankelijk van de variablen die meegegeven worden. Als je er een class van maakt kun je nog extra instellingen meegeven via andere methodes (zoals bijvoorbeeld het meegeven van een logger aan het object). Maar dit staat toch helemaal los van je vraag over het uitvoeren van logica in de constructor?
>> Stel dat je de Processor class hebt en het enige wat je in de constructor doet is het request setten, en verder niks. In principe is de class zelf nu dus gebruiksklaar.
Zoals je zelf al zegt: je doet het in dit geval al in de constructor, omdat je Processor anders ongeldig is.
Dat is het doorslaggevende criterium: de constructor levert een geldig object op. De enkele aanroep van de klasse met new ... moet een valid object opleveren. Daar moet niet nog eens init() of iets dergelijks voor initialiseren of een andere vorm van het "booten" of "opstarten" van het object overheen.
>> Nu is de volgende stap in het proces dat je een aantal dingen wilt initialiseren, je wilt bijv. de services laden en je wilt wat gegevens inladen (bijv. paden). In feite is dit dus ook een vorm van initialiseren. Hoort dit dan ook thuis in de constructor?
Dat klinkt als een verzameling van verschillende taken en verschillende verantwoordelijkheden — en dus verschillende klassen. Maar dit is strikt genomen meer configureren dan initialiseren.
Even een voorbeeldje met een databaseverbinding. Die open je liever zó:
<?php
$dbh = new Database($servername, $username, $password);
?>
dan zo:
<?php
$dbh = new Database();
$dbh->setServerByName($servername);
$dbh->setUserName($username);
$dbh->setPassword($password);
$dbh->connect();
?>
Het kán wel op de tweede manier — en incidenteel heb je het misschien zelfs per se nodig — maar fraai is anders.
>> Bij een statische methode afhankelijk ben je afhankelijk van de variablen die meegegeven worden. Als je er een class van maakt kun je nog extra instellingen meegeven via andere methodes (zoals bijvoorbeeld het meegeven van een logger aan het object). Maar dit staat toch helemaal los van je vraag over het uitvoeren van logica in de constructor?
Ik snap het nog steeds niet (sorry). Mijn vraag was of de constructor logica mag uitvoeren. Het antwoord daarop is nee. Oké prima. Maar dan moet er dus wel een execute method worden aangeroepen van buitenaf. Toen zei jij dat je dat dan met een statische methode zou doen:
<?php
Processor::execute($request);
?>
Op zich vind ik dat wel mooi om op deze manier te doen, maar mijn vraag is waarom je voor een statische methode kiest in plaats van dit:
<?php
$processor = new Processor($request);
$processor->execute();
?>
Misschien moet ik de vraag iets anders stellen. Wanneer kies je voor een statische aanroep?
@Ward:
>> Dat klinkt als een verzameling van verschillende taken en verschillende verantwoordelijkheden — en dus verschillende klassen. Maar dit is strikt genomen meer configureren dan initialiseren.
Klopt, het wordt ook door verschillende classes uitgevoerd, maar het moet vanuit de processor worden getriggerd. Deze handelingen moeten gebeuren voordat de execute method wordt aangeroepen. Dus dan kan ik het vanuit de constructor doen... maar dan doet de constructor dus eigenlijk te veel, of ik ga de functie handmatig aanroepen, maar dan krijg je dus weer een extra init() aanroep en dat wilden we ook niet. Het enige dat dan overblijft, is dat de execute method die handelingen gaat uitvoeren/triggeren. Ik denk dat dat dan de beste oplossing is.
<?php
Processor::execute($request);
?>
Op zich vind ik dat wel mooi om op deze manier te doen, maar mijn vraag is waarom je voor een statische methode kiest in plaats van dit:
<?php
$processor = new Processor($request);
$processor->execute();
?>
Ik keek naar je gegeven voorbeeld, je hebt een class die 1 variable krijgt ($request) en maar 1 ding doet (execute). Geen extra dependencies of whatsoever. Maar goed hierover verschillen de meningen. Er is geen één manier binnen het programmeren, en ik zou gaan wat voor jezelf het duidelijkst is
Maar zo'n oplossing gebruik je dus als een class maar 1 ding kan doen (1 method heef) en verder geen dependencies heeft. Correct?
Die dependencies zijn nu juist een deel van het probleem: je hebt een kernelprocessor met afhankelijkheden die dóór die afhankelijkheden eerst moet worden geconfigureerd voordat deze kan worden geïnitialiseerd :-)
Dependencies zijn ook een deel van de oplossing, want je kunt de drie verantwoordelijkheden instellen/controleren/uitvoeren ook splitsen, bijvoorbeeld in:
<?php
class Processor
{
public static function execute(ProcessorRequest $request)
{
if (true === ProcessorRequestValidator::isValid($request)) {
// ...
}
}
}
?>