9: Instantiebeheer
Phlo gebruikt zijn eigen instance manager om objecten efficiënt en voorspelbaar te initialiseren en opnieuw te gebruiken. Dit systeem bepaalt wanneer controller code wordt uitgevoerd, hoe instanties worden opgeslagen en hoe circulaire referenties worden voorkomen.
9.1: De basisprincipes
Wanneer je een .phlo-bestand definieert, verandert de build-fase het in een klasse. Elke aanroep naar een object via %name gaat via de instance manager (phlo() in /phlo/phlo.php).
Voorbeeld:
prop title = 'Welkom'
route GET home => $this->main
method main => view($this->home)
view home:
<h1>$this->title</h1>
Wanneer de route /home wordt aangevraagd:
- De instance manager controleert of er al een instantie van deze klasse bestaat.
- Zo niet, dan wordt deze gemaakt en opgeslagen.
- Na creatie wordt de controllercode uitgevoerd (zie §8.2).
- Vervolgens wordt de aangevraagde methode aangeroepen.
9.2: Controller code
Alle code in een .phlo-bestand die niet behoort tot route, prop, static, method, function, view, <style> of <script> is controller code. Deze code wordt uitgevoerd na de instantie zodra de instantie volledig bestaat.
Voorbeeld:
prop ready = false
%session->start()
$this->ready = true
De laatste twee regels zijn controller code omdat ze op het hoogste niveau staan.
- Deze code wordt één keer uitgevoerd, wanneer de instantie voor het eerst wordt aangemaakt.
- Het verschil met
__constructis dat de instantie volledig bestaat tegen de tijd dat de controller code wordt uitgevoerd, wat cirkelreferenties en onvolledige objecten voorkomt.
9.3: De rol van `__handle()`
Phlo genereert een speciale __handle() methode voor elke klasse. De instantiebeheerder roept deze aan wanneer een instantie wordt opgevraagd via %name.
__handle():
- voert de controllercode uit als deze nog niet is uitgevoerd;
- zorgt ervoor dat props en statics correct beschikbaar zijn;
- cache de instantie voor volgende aanroepen.
Je roept __handle() nooit zelf aan of overschrijft deze; het is onderdeel van de gegenereerde klasse en de instantiebeheerder.
9.4: Luie initialisatie
Omdat controllercode alleen na constructie wordt uitgevoerd, kunnen instanties elkaar verwijzen zonder ongewenste recursieve creatie te activeren.
Voorbeeld:
a.phlo:
prop message = 'A ready'
b.phlo:
prop message = 'B ready'
main.phlo:
route GET test => $this->show
method show {
dx(%a->message, %b->message)
}
%aen%bworden lui aangemaakt.- De controllercode in beide bestanden wordt uitgevoerd zodra hun instantie volledig bestaat.
- Je kunt vrijelijk instanties van elkaar verwijzen, omdat de instantie al bestaat voordat de controllercode wordt uitgevoerd.
9.5: De obj basis klasse: powertools
Elke gecompileerde klasse breidt obj uit, en obj is meer dan __get/__set. Dit zijn de tools die je gebruikt wanneer een klasse dynamisch moet functioneren.
Interceptie haakjes. Implementeer objCall, objGet of objSet om de toegangsketen te vangen. Het retourneren van null valt terug op het normale gedrag; alles wat niet-null is, kortsluit:
method objGet($key) => $this->cache[$key] ?? null
method objCall($method, ...$args) => str_starts_with($method, 'find') ? $this->finder($method, $args) : null
method objSet($key, $value) => $key === 'id' ? true : null
objGet wordt uitgevoerd voordat data/closure/methode/prop lookup plaatsvindt bij elke lezing, objCall bij elke onbekende methode-aanroep, en objSet voordat elke schrijfoperatie plaatsvindt (een niet-null retour onderdrukt de schrijfoperatie). Dit is het mechanisme achter decorators, lazy loading en read-only guards.
Gebonden closures. Wijs een closure toe en deze bindt zich aan de instantie: $obj->greet = fn() => "Hi $this->name", later draait $obj->greet() met $this gebonden. Handig voor per-instantie gedrag zonder subclassing.
Data API. objImport(name: 'x', age: 3) wijst in bulk toe en retourneert $this (ketenbaar). objKeys(), objValues() en objLength() inspecteren de data; objClear() wist het. Itereren over een obj (foreach $record AS $key => $value) en json_encode($record) onthullen precies de opgeslagen data. Elke schrijfoperatie schakelt objChanged in, de dirty flag die de ORM gebruikt om te beslissen of objSave iets schrijft.
Gecachede computed props. prop x => ... cachet bij de eerste toegang; de argumentvorm cachet per argumentenset. Hetzelfde geldt voor computed statics, gecached per klasse.
Worker persistentie. prop objPers = true zorgt ervoor dat een instantie overleeft tussen requests in worker-modus: het phlo() register houdt alleen objPers instanties vast bij zijn reset per request. Geschikt voor DB-verbindingen en geparsed configuraties; ongeschikt voor alles wat request- of gebruikersgebonden is.
Les. Een gewone prop in een bovenliggende klasse SCHADUWT een computed prop in een kind.
prop dir = voidin een abstracte bovenliggende klasse compileert naar een echte PHP-eigenschap, zodat de getter van een kindprop dir => guidenooit wordt geraadpleegd:$this->dirleest stilletjesvoid. Wanneer kinderen moeten overschrijven met een computed prop, verklaar de bovenliggende prop ook als computed:prop dir => void.
9.6: Best practices
- Gebruik controllercode voor initiële setup, niet voor op verzoek gebaseerde logica.
- Plaats controllercode bovenaan of direct onder props voor leesbaarheid.
- Vermijd bijeffecten in
__construct; gebruik controllercode in plaats van aangepaste constructeurs. - Laat instanties zichzelf lui initialiseren via
%namein plaats van ze handmatig te creëren. - Gebruik controllercode opzettelijk om circulaire referenties op te lossen.