Gebruikt $this van parent class mogelijk?

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Bastiaan Haastrecht

Bastiaan Haastrecht

21/01/2020 10:23:11
Quote Anchor link
Hoi,

Ik ben opzoek naar de manier om het volgende op de best-pratize aan te pakken.

Ik heb een class waar een $this in bestaat. Vanuit deze class maak ik een nieuwe instance aan van een andere class. Binnen deze tweede class wil ik gebruik maken van de $this van de eerste class.

De manier waarop ik het nu doe is als volgt:

```
Class Eerste {
public function een_funtie() {
$tweedeClass = new Tweede();
$resultaat = $tweedeClass->nog_een_functie(this);
}
}

Class Tweede {
public function nog_een_functie($eersteClass) {
$doeIets = $eersteClass;
}
}
```

Is het mogelijk dit op een andere manier te doen? De tweede class wordt namelijk ook gebruikt door andere stukken code, dus ik zou $this niet graag het als een argument willen meegeven. Uiteraard zou ik de tweede class kunnen extenden, maar dat wil ik niet omdat de eerste class eigenlijk een Trait is van een vendor module.

Ik kijk uit naar jullie reacties.

Bvd, mvg,
Bastiaan
Gewijzigd op 21/01/2020 10:25:20 door Bastiaan Haastrecht
 
PHP hulp

PHP hulp

29/03/2024 01:24:47
 
Thom nvt

Thom nvt

21/01/2020 10:34:55
Quote Anchor link
Zet je code even tussen code tags, dat maakt het leesbaarder.

Wat je beschrijft heet "Dependency injection", je 2e class heeft een afhankelijkheid van je eerste class.

Dit kun je op meerdere manieren oplossen, jouw oplossing is daar 1 van maar wat ik persoonlijk netter vind is het volgende:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

Class Eerste {
    public funcion een_functie() {
        $tweedeClass = new Tweede($this);
        $resultaat = $tweedeClass->nog_een_functie();
    }
}


Class Tweede {
    protected $eersteClass;

    public function __construct(Eerste $eerste) {
        $this->eersteClass = $eerste;
    }


    public function nog_een_functie() {
        $doelets = $this->eersteClass;
    }
}

?>


Let wel op dat je dit niet te ver door trekt, dependencies die "gestapeld" zijn worden snel onoverzichtelijk.
Daarnaast moet je uitkijken voor Circular dependencies, anders raakt je code in een oneindige lus.

Zoek eens op Dependency injection (DI), het factory pattern en service managers/containers. Er zijn tal van mooie oplossingen voor.
Gewijzigd op 21/01/2020 10:36:24 door Thom nvt
 
Bastiaan Haastrecht

Bastiaan Haastrecht

21/01/2020 12:23:23
Quote Anchor link
Juist, Dependency injection is dus de juiste term. Inderdaad, door het in de __construct te plaatsen ziet het er netter uit.

Dank je wel, hier kan ik mee verder!
 
Thomas van den Heuvel

Thomas van den Heuvel

21/01/2020 17:38:56
Quote Anchor link
Quote:
dus ik zou $this niet graag het als een argument willen meegeven.

Waarom niet? Dat is namelijk precies wat je doet? Of bedoel je: deze wil ik niet elke keer opnieuw als argument meegeven? Dan doe je dat eenmalig bij de constructie en onthoud je de referentie zoals hierboven staat beschreven. Dit is ook vrij normaal: door de scope kent de class Tweede de class Eerste niet tenzij je hem daar op een of andere manier op attent maakt.
Quote:
De tweede class wordt namelijk ook gebruikt door andere stukken code

Classes worden gebruikt door middel van hun instanties (objecten van de class) (als je static methoden even buiten beschouwing laat). Op dit moment maak je een object van Tweede aan binnen de Eerste class, en daarmee is dit object alleen bekend binnen de scope van (een object van) de class Eerste. Zou het dan niet logischer zijn om dit om te draaien en een object van Eerste aan te maken binnen een (globaler beschikbaar) object van Tweede? Want anders zou je opnieuw deze instanties moeten doorgeven aan andere code/objecten/classes. Als het de Tweede class is die je elders wilt hergebruiken - nu zit het object verpakt in een ander object (van class Eerste). Of je creëert deze objecten los van elkaar, en je combineert ze op een later tijdstip. Meerdere opties mogelijk.

Het hangt natuurlijk van de rest van de code af en de interacties tussen de objecten hoe je dit structureert, dus het is moeilijk om op voorhand precies te zeggen hoe je dit aanpakt.

Het bovenstaande voorbeeld is nogal abstract. Heb je een concrete case?
 
Bastiaan Haastrecht

Bastiaan Haastrecht

21/01/2020 20:36:31
Quote Anchor link
De case is als volgt. Ik heb een app gemaakt met Laravel 5.8, daarin maak ik gebruik van jobs/queue's om bepaalde opdrachten op schedule basis te laten uitvoeren. Standaard heeft Laravel geen mogelijkheid om de job te tracken, daarom maak ik gebruik van een composer package 'imTigger/laravel-job-status'. Deze wordt via een use in de Job Class ingeladen. Bij het starten van een Job maakt deze Trait via een Model een DB regel (MySQL) aan. Mocht er tijdens de job iets misgaan, dan kan ik daar de rede uit halen. Het is ook mogelijk om tijdens de run de 'output' te vullen. Echter de setOutput method is een vervanging van het veld. Ik heb behoefte om tijdens het draaien van een Job wat sub statussen op te slaan, berichten voor achteraf debuggen van de run. Ik log dit al via Monolog, maar dat is later lastiger terug te chainen. Daarom heb ik in de Job class een extra method gemaakt addOutput. Deze merged de huidige output met de nieuwe output en slaat het via het bestaande model weer op. Dit werkt dikke prima, binnen de eigen Job class. Maar veel van mijn Jobs die laden één of meerdere classes om daar zaken in uit te voeren. Nu wil ik binnen de Child classes dus ook berichten kunnen stoppen in die jobstatus. Ik zou een eigen class kunnen maken die het Model vult, maar dan heb ik het JobId nodig om de juiste regel te vullen. Die job Id zit ook in de parent Job class. Dus vandaar dat ik opzoek ben naar een mooie manier om die addOutput method door te trekken naar diverse andere classes.

Ik waardeer jullie input, ik ben geen opgeleide programmeur maar kan mijn weg inmiddels in php (en overige talen) goed vinden, wat ik alleen niet heb is gefundeerde achtergrond over hoe je bepaalde cases moet aanpakken. Nooit te oud om wat te leren.
Gewijzigd op 21/01/2020 20:38:11 door Bastiaan Haastrecht
 
Thom nvt

Thom nvt

21/01/2020 21:55:52
Quote Anchor link
Dat is een wat lastig leesbare muur aan tekst maar ik denk dat ik hem snap.

Zo te lezen wil een aanpassing doen aan een bestaande class uit een composer package zodat je functionaliteit kan toevoegen.

Aanpassingen aan code die niet van jou is moet je niet doen, dan kun je later die package niet meer updaten.
In plaats daarvan zou je de class moeten extenden en de method die de regels wegschrijft moeten overschrijven met jouw eigen code. Vervolgens gebruik je alleen jouw eigen instantie van die class zodat de gewenste functionaliteit gebruikt kan worden en voor de rest het "origineel" gebruikt word.

Op die manier volg pas je niets aan in de externe code en heb je toch de functionaliteit die je wil.

Als ik het verkeerd begrijp heb ik nog wat meer uitleg nodig of wellicht een representatief code voorbeeld (Heb je het op GitHub/Bitbucket/GitLab staan bijv?)
 
Bastiaan Haastrecht

Bastiaan Haastrecht

22/01/2020 09:48:45
Quote Anchor link
Ik pas beslist niet de composer package aan, ik snap hoe dat werkt incl extending enz.

In laravel maak ik een job aan, daar voeg ik de betreffende composer package als een Trait in toe. Vervolgens in deze job, waar dus alle methods van die Trait nu onder $this beschikbaar zijn voeg ik in de job een method addInput() toe.

Ik kan niet de volledige app delen, maar heb een gist aangemaakt om je het concept te laten zien.
https://gist.github.com/BasvanH/540d92555877345f905ac527ba3f6114

Wat ik persoonlijk mooier zou vinden is dat ik in de TestClass een Trait zou includen die de jobstatus van output zou kunnen voorzien. Alleen moet ik dan wel het jobid binnen die Trait hebben anders kan ik niet de regel in de db vinden.

Toevoeging op 23/01/2020 08:40:34:

Ik heb het mooier opgelost. Ik heb een eigen trait gemaakt die bovenop de Laravel Log Facade ligt (onderwater Monolog). Ik vang daarmee de Log::errors berichten af, stop ze in een global static variable die ik vervolgens vanuit de job kan uitlezen. Zo hoef ik niets te bruggen. In mijn trait forward ik alle overige Log calls af via __callStatic Magic Method.

Toch bedankt voor het meedenken.
 
Thom nvt

Thom nvt

23/01/2020 10:27:55
Quote Anchor link
Dat is ook zeker een oplossing.

Pas wel op met global static variabelen, dat is niet echt de OOP manier.
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.