Ik heb een autoload functie in een class staan. Nu heb ik in die class ook een register method staan die die de autoload functie, jawel... registreert :)
In mijn code hoef ik dan alleen dit te doen:
<?php
$autoloader = new Autoloader();
$autoloader->register();
?>
Een tijdje terug hadden we het in een ander topic over het constructen van classes en wanneer je dat doet. Ward gaf toen aan dat als je een class hebt waarbij je altijd dit doet:
<?php
$foo = new Foo();
$foo->doFoo();
?>
Dat je dan net zo goed doFoo() vanuit de constructor kunt laten uitvoeren.
Bij mijn autoloader class heb je nu zo'n zelfde situatie. De enige method die je kunt aanroepen is register. Dus het enige wat je met die class kunt doen is dit:
<?php
$autoloader = new Autoloader();
$autoloader->register();
?>
Nu vraag ik me dus af of ik dan niet beter de register method vanuit de constructor kan triggeren. Als ik dan de autoloader wil registreren, dan hoef ik alleen nog maar dit te doen:
<?php
new Autoloader();
?>
Op zich wel lekker kort, maar is dit gebruikelijk? In principe zie je nu in de code niet wat er gebeurt, maar dat zou je met commentaar kunnen ondervangen:
<?php
// Register the autoload method.
new Autoloader();
?>
Graag jullie reactie.
Echter... welk voorbeeld is logischer? Het enige wat de KersVerwijderaar class kan is kersen verwijderen, en dat kan ook maar 1x, want daarna zijn ze al verwijderd. Vanuit dat oogpunt is het dus logischer dat de constructor opdracht geeft om de kersen te verwijderen. Alleen je ziet dit dan niet terug in de code zoals in het 2e voorbeeld.
In dit specifieke voorbeeld, wat zou dan de juiste variant zijn. Ga je voor de logische variant (de 1e optie) die precies doet wat ie moet doen, of ga je voor de 2e variant, waarbij je eigenlijk onnodig een functie moet aanroepen, maar waardoor je wel weer duidelijker ziet wat er gebeurt?
Een 3e variant biedt je beide in één expressie: logisch en inzichtelijk.
Een autoloader dient voor gemakt, zodat je ongestoord classes kunt aanroepen. Op de manier hoe jij het doet, moet je nu constant autoloaders gaan registeren en unregisteren. Maak je het jezelf dan niet heel lastig?
<?php
// register default autoloader
// code...
// Er treedt een Exception op..
// De exception moet gemaild worden...
// register de mail autoloader
// stuur een mail
// unregister de mail autoloader
// code...
// er moet een pdf gemaakt worden
// register de pdf autoloader
// maak een pdf
// het creëren van de pdf gaat mis
// Er treedt een Exception op..
// De exception moet gemaild worden...
// register de mail autoloader
// stuur een mail
// unregister de mail autoloader
// unregister de pdf autoloader
// log de Exception
// register de logger autoloader
// log de Exception
// unregister de logger autoloader
// enz.
?>
Lijkt me wat omslachtig...
Zo omslachtig is dat soms inderdaad. Verwerk maar eens een bestelling voor een webwinkel. Een geslaagde betaling (namespace betaalprovider) leidt tot het mailen (namespace mailer) van een PDF (namespace PDF-framework) en een order (namespace fulfilment) die je meteen inschiet bij de vervoerder (PostNL namespace). En ondertussen moet je eigen framework nog iets fatsoenlijks op het scherm van de klant toveren...
Die class kan dus niks anders dan kersen uit de taart halen. Je kunt verder niks bepalen. Stop je dan de functie die de kersen uit de taart haalt in de constructor? Of moet je een method aanroepen?
Worden de kersen door (in opdracht van) de constructor verwijderd:
<?php
$kers_verwijderaar = new KersVerwijderaar($taart); // op dit moment worden de kersen via de constructor direct verwijderd
$kale_taart = $kers_verwijderaar->getTaart();
?>
of geef je de opdracht tot het verwijderen van de kersen zelf?
<?php
$kers_verwijderaar = new KersVerwijderaar($taart); // op dit moment zitten de kersen er nog op!
$kers_verwijderaar->verwijderKersen(); // nu pas worden de kersen verwijderd
$kale_taart = $kers_verwijderaar->getTaart();
?>
Ik ga proberen mijn vraag zo duidelijk mogelijk te formuleren. In het laatste voorbeeld zie je in de code dat de kersen worden verwijderd. Immers er staat $kers_verwijderaar->verwijderKersen(); Je zou dus kunnen zeggen dat deze code misschien duidelijker is dan het 1e voorbeeld waarin je dit niet kunt zien.
Echter... welk voorbeeld is logischer? Het enige wat de KersVerwijderaar class kan is kersen verwijderen, en dat kan ook maar 1x, want daarna zijn ze al verwijderd. Vanuit dat oogpunt is het dus logischer dat de constructor opdracht geeft om de kersen te verwijderen. Alleen je ziet dit dan niet terug in de code zoals in het 2e voorbeeld.
In dit specifieke voorbeeld, wat zou dan de juiste variant zijn. Ga je voor de logische variant (de 1e optie) die precies doet wat ie moet doen, of ga je voor de 2e variant, waarbij je eigenlijk onnodig een functie moet aanroepen, maar waardoor je wel weer duidelijker ziet wat er gebeurt?
Dit klinkt echt alsof je puur een object wilt aanmaken omdat het kan. Wat voor redenen heb jij dat dit een object MOET worden en het dus geen functie/static method kan zijn?
>> Zo omslachtig is dat soms inderdaad. Verwerk maar eens een bestelling voor een webwinkel. Een geslaagde betaling (namespace betaalprovider) leidt tot het mailen (namespace mailer) van een PDF (namespace PDF-framework) en een order (namespace fulfilment) die je meteen inschiet bij de vervoerder (PostNL namespace). En ondertussen moet je eigen framework nog iets fatsoenlijks op het scherm van de klant toveren...
Maar ga je die namespaces dan echt pas registreren op het moment dat je ze nodig hebt? En dan als bijv. de mail verstuurd is, ga je dan de e-mailnamespace weer unregisteren? Registreer je niet alles gewoon in 1x, waarbij je de belangrijkste namespaces als eerst registreert?
>> Dit klinkt echt alsof je puur een object wilt aanmaken omdat het kan. Wat voor redenen heb jij dat dit een object MOET worden en het dus geen functie/static method kan zijn?
Dat is een goede vraag. Het voorbeeld in de praktijk is dat ik bijv. een aantal services wil configureren op het moment dat deze nog niet gecached zijn. Ik heb een class die de betreffende services ophaalt uit de cache, maar als het cache bestand niet bestaat dan moeten een aantal services geconfigureerd worden. Hier wil ik een aparte class voor gebruiken. (Wat ik nu vertel heeft trouwens betrekking op het initialisatieproces van het request.)
Feitelijk krijg je dus zoiets als dit:
<?php
class Foo {
public function get() {
// haal de services op uit de cache
// indien geen cache:
$services_configurator = new ServiceConfigurator();
return $services_configurator->get();
}
}
class ServiceConfigurator {
private $services;
public function __construct() {
$this->configure();
}
public function configure() {
// configure the services
$this->services = $services;
}
public function get() {
return $this->services;
}
}
?>
Dit is ongeveer het idee. Hier lijkt het me logischer om de method configure() in de constructor te stoppen, in plaats van deze handmatig aan te roepen.
P.s. ik ben m'n autoloader dynamisch aan het maken... Ik ben nog wel even benieuwd. Ik wil ook een PSR0 autoload method toevoegen, maar aan welke exacte eisen moet deze voldoen? Weet iemand dat?
P.s. ik ben m'n autoloader dynamisch aan het maken... Ik ben nog wel even benieuwd. Ik wil ook een PSR0 autoload method toevoegen, maar aan welke exacte eisen moet deze voldoen? Weet iemand dat?
Ik dacht trouwens dat een class-naam niet met een slash behoort te beginnen?
Ik gebruik Foo\Bar\FooBar, maar in de voorbeelden zie ik bijv. \Symfony\Core\Request
Moet een class wel of niet met een slash beginnen?Sorry, ik zat te slapen.