Gebruik van properties over models heen

Pagina: 1
Acties:

Onderwerpen


  • Tjolk
  • Registratie: Juni 2007
  • Laatst online: 15:09
Ik had onlangs een discussie over het volgende, en ben eigenlijk wel benieuwd naar meningen van anderen.

Wij gebruiken CodeIgniter als framework voor onze PHP applicatie. Hierin heb je direct al scheiding van models, views en controlllers.
Nu is het zo dat ik binnen model X public properties nodig heb van model Y. Beide models worden via de controller ingeladen aangezien ik ze sowieso toch beide nodig heb. Dat kun je dan op verschillende manieren aanvliegen.

Methode 1:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
<?php

// Controller
$foo = $this->modelY->foo;
$bar = $this->modelX->baz($foo);

// modelX
public function baz($foo) {
    return $foo;
}

?>


Methode 2:
PHP:
1
2
3
4
5
6
7
8
9
10
11
<?php

// Controller
$bar = $this->modelX->baz();

// modelX
public function baz() {
    return $this->modelY->foo;
}

?>

Natuurlijk doet $modelX->baz() meer dan een variabele returnen, maar dat terzijde. Punt is dat de public properties uit modelY op diverse plaatsen in andere models gebruikt worden.

De vraag is nu: wat is 'beter'? Methode 1 scheidt duidelijker de models van elkaar en laat de communicatie tussen beide geheel door de controller lopen. Methode 2 is echter efficiënter omdat het een variabele scheelt in het geheugen en gewoon minder code vraagt (als is dat marginaal natuurlijk).

Tjolk is lekker. overal en altijd.


  • Morax
  • Registratie: Mei 2002
  • Laatst online: 17:02
De startpost lezend is er dus een afhankelijkheid is tussen 2 models. Het ene model levert een waarde op die afhankelijk is van de waarde in een ander model.

Mijns inziens zou die afhankelijkheid in het betreffende model moeten worden gedefinieerd, niet in de controller, die hoeft niet van die afhankelijkheid af te weten. Zeker niet als er vaker gebruik gemaakt wordt van die afhankelijkheid.

What do you mean I have no life? I am a gamer, I got millions!


  • DJMaze
  • Registratie: Juni 2002
  • Niet online
Ger schreef op donderdag 08 september 2016 @ 11:15:
Methode 2 is echter efficiënter omdat het een variabele scheelt in het geheugen en gewoon minder code vraagt (als is dat marginaal natuurlijk).
Hoezo scheelt het een variabele?
PHP:
1
$bar = $this->modelX->baz($this->modelY->foo);

De impact in jouw en dit voorbeeld is totaal niet benoemenswaardig.

Het kan ook nog zo:
PHP:
1
2
3
4
5
$bar = $this->modelX->baz($this->modelY);

public function baz(\namespace\ModelY $modelY) {
    return $modelY->foo;
}


Oh en als die afhankelijkheid er meer is dan lijkt mij een trait op zijn plaats.

[ Voor 9% gewijzigd door DJMaze op 08-09-2016 15:49 ]

Maak je niet druk, dat doet de compressor maar


Acties:
  • 0 Henk 'm!

  • Tjolk
  • Registratie: Juni 2007
  • Laatst online: 15:09
Dank beiden. En ik moet eerlijk zeggen: een (hele) tijd terug heb ik wel gelezen over traits, maar ik kon ze destijds niet gebruiken omdat we nog op 5.3 draaiden. Daarna nooit meer aan gedacht totdat ik het las van DJMaze. Ik zie ze eigenlijk ook nooit in het wild gebruikt worden. Andere recentere PHP functies wel, maar dit werkelijk nog nooit.

Ik neem dit mee als bagage. Het komt toch puur neer op voorkeur dus ik ga voor nu gewoon voor zoveel mogelijk consistentie binnen de complete code van het project. Dat is mij dan meer waard dan micro-optimalisatie. :)

Tjolk is lekker. overal en altijd.


Acties:
  • 0 Henk 'm!

  • storeman
  • Registratie: April 2004
  • Laatst online: 12-09 11:48
Volgens mij is hier geen zinnig antwoord op te geven. Het hangt heel erg af van de situatie. Als er een duidelijke afhankelijk is tussen de twee objecten, dan is het ook logisch om het object mee te geven. Bijvoorbeeld een persoon en een voertuig, die kunnen op meerdere manieren interactie met elkaar aangaan en het is dan ook logisch dat de een de ander leert kennen.

Als het echt een functie is die iets doet met de input, bijvoorbeeld een factor toepassen, dan maakt het niet uit vanuit welk model het komt. Dan wil je een getal aanpassen met data uit het model. Uit welk model de data komt is dan totaal niet relevant.

Je moet volgens mij altijd nadenken, is deze functie logisch op mijn model, met name qua verantwoordelijkheid.

"Chaos kan niet uit de hand lopen"


Acties:
  • +1 Henk 'm!

  • menzo.io
  • Registratie: September 2016
  • Laatst online: 03-08 20:56
Ik denk dat er iets meer context nodig is over de implementatie van functie baz in je model.

Het liefst wil je alle code zo los gekoppeld mogelijk hebben. Dus voor de methode baz zou je in de parameters alleen de variabelen willen hebben die er daadwerkelijk toe doen.

Zo heb je nu bijvoorbeeld 2 modellen. $foo & $bar. $bar heeft de methode ->baz die iets met de mee gegeven waarde $x doet.

Als het model $foo verder geen enkele relevantie heeft binnen de implementatie van methode ->baz, wil je deze ook niet onnodig gaan koppelen binnen de methode.

Stel je wil in de toekomst een waarde van een ander model meegeven aan methode baz, loop je tegen problemen aan omdat ->baz direct gekoppeld is aan de implementatie van model $foo.

Om deze rede is de implementatie van functie baz in model $bar belangrijk.


Twee use cases:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php

Class Bar {
    
    /**
     * @param  int $x
     * @return int    multiplied value of x
     */
    public function baz($multiply) {
        return $x * 2;
    }

}


Class Foo {
    
    public $age = 0;

    public function __construct($age) {
        $this->age = $age;
    }

}


$bar = new Bar();
$p1 = new Foo(10);

$bar->baz($p1->age);
$bar->baz(12)


Omdat de methode baz puur met integers werkt, is het een logisch besluit om de implementatie van $foo buiten de methode te houden.

Maar het zou ook kunnen dat je doormiddel van een Interface, verschillende implementaties hebt van hetzelfde type model. Hierbij zou het kunnen dat $bar een methode van je interface aanroept, zonder dat de implementatie van die methode vastgesteld is.

Door interfaces mee te geven, kunnen andere ontwikkelaars, of jijzelf als je later weer aan het project werkt direct zien hoe methode ->baz gebruikt hoort te worden. En is het altijd mogelijk om nieuwe versies van je Interface toe te voegen aan je project.


code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php

Class Bar {
    
    /**
     * @param  Tree $x
     */
    public function baz(Tree $tree) {
        $tree->addBranch(rand())
    }

}


interface Tree {
    public function addBranch($branch_id);
}

Class Foo implements Tree {
    private $roots[];
    public function addBranch($branch_id) {
        $this->roots[]= $banch_id;
    }
}

Class SuperFoo implements Tree {
    private $base;
    public function addBranch($branch_id){
        $this->base[] = $branch_id
    }

}

$bar = new Bar();
$foo = new Foo();
$super_foo = new SuperFoo();

$bar->baz($foo);
$bar->baz($super_foo);


Edit: Ik denk dat je eens naar Domain Driven design moet kijken en Single Responsibility.

DDD: http://code.tutsplus.com/...-driven-design--net-25773
Single Responsibility: http://code.tutsplus.com/...lity-principle--net-36074

[ Voor 5% gewijzigd door menzo.io op 14-09-2016 03:57 . Reden: Meer Resources ]


Acties:
  • +1 Henk 'm!

  • DJMaze
  • Registratie: Juni 2002
  • Niet online
Ger schreef op maandag 12 september 2016 @ 16:15:
Ik zie ze eigenlijk ook nooit in het wild gebruikt worden. Andere recentere PHP functies wel, maar dit werkelijk nog nooit.
Ik gebruik ze en het is een verademing. De belangrijkste die ik gebruik is https://bitbucket.org/djm...eviewer=file-view-default

Hiermee kan ik aan elke class een events/hook systeem hangen.

Denk hierbij aan:
PHP:
1
2
3
4
5
6
7
8
class User { use Events; }
$user = new User();
$user->addEventListener('login', function(\Poodle\Events\Event $event){ /* do something */ });
$user->addEventListener('logout', function(\Poodle\Events\Event $event){ /* do something */ });

class Session { use Events; }
$user->addEventListener('beforeWriteClose', function(\Poodle\Events\Event $event){ /* do something */ });
$user->addEventListener('afterStart', function(\Poodle\Events\Event $event){ /* do something */ });


Ik hoef dan niet de code voor elke class opnieuw te maken.

Dit is vooral handig voor Classes die al een Parent hebben (want twee parents kan niet) zoals:
PHP:
1
class XMLLezer extends \XMLReader { use Events; }

[ Voor 6% gewijzigd door DJMaze op 14-09-2016 19:33 ]

Maak je niet druk, dat doet de compressor maar

Pagina: 1