[oop] best practice, methods met "dubbele" functie?

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Ozzie PHP

Ozzie PHP

24/11/2013 01:00:20
Quote Anchor link
Ola,

Is het volgens jullie wel of niet een goed idee om methods te maken die een "dubbele" functie kunnen uitvoeren? Of is dit een kwestie van persoonlijke smaak?

Bijvoorbeeld, stel we slaan in een class de properties van een product op. Via $this->get($id) kunnen we een property ophalen. Stel nu dat ik alle properties tegelijk wil ophalen, dan zou ik dit kunnen doen:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
$this
->getAll();
?>

Maar ik zou ook dit kunnen doen:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
$this
->get();
?>

Merk op dat ik geen ID meegeef. Door geen specifieke ID mee te geven, krijg ik alle IDs terug. Is dit wel of niet een goed idee?

Hetzelfde geldt voor bijvoorbeeld een delete method:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
<?php
$this
->delete('foo'); // verwijdert foo
$this->delete(); // verwijdert alles
?>

Ik ben benieuwd wat jullie vinden.
 
PHP hulp

PHP hulp

22/12/2024 09:40:59
 
Local Dev

Local Dev

24/11/2013 01:37:49
Quote Anchor link
Quote:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
<?php
$this
->delete('foo'); // verwijdert foo
$this->delete(); // verwijdert alles
?>


Lijkt me geen goed idee, in 1 keer alles verwijderd, ook als dit niet de bedoeling was?

Ik zou voor het ophalen/verwijderen van alles andere namen gebruiken dan voor het ophalen data/verwijderen van 1 object.

persoonlijk zou ik gaan voor:
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
<?php

/**
 * Get object by id
*/

public function getById($id)
{}


/**
 * Get array | objects
*/

public function fetchAll()
{}

?>
Gewijzigd op 24/11/2013 01:42:15 door Local Dev
 
Ozzie PHP

Ozzie PHP

24/11/2013 01:40:28
Quote Anchor link
@Local:

Dankjewel voor je reactie. En geldt dat alleen voor een delete functie? Of ook voor bijv. een get/getAll functie?
 
Local Dev

Local Dev

24/11/2013 01:46:00
Quote Anchor link
Geld voor beide, wanneer je een bepaalde functie aanroept, verwacht je naar mijn mening een bepaald resultaat, een object, string, of een array, maar naar mijn mening moet je wel de controle behouden over wat de functie returned, in jouw case kan je voor onverwachte resultaten komen te staan.
 
Ozzie PHP

Ozzie PHP

24/11/2013 01:54:20
Quote Anchor link
Dat is dus inderdaad ook waarover ik nu in dubio zit. Van de ene kant is het handig om maar 1 method get() te hebben, omdat ik dan maar 1 method hoef te onthouden :) Maar het is inderdaad de vraag of die ene method dan niet teveel hooi op z'n vork neemt.

Ik zie dat je je bericht nog had ge-edit. Ik gebruik zelf niet getById($id), maar get($id). Ik haal normaal gesproken alles op, op basis van een ID, dus dat hoef ik dan niet specifiek in de methodnaam te laten terugkomen. Alleen wanneer er meerdere mogelijkheden zijn om iets op te halen, pas dan zou ik voor zo'n uitbreiding kiezen. Bijv. een user class met getById en getByName. En als ik alles wil getten dan zou ik niet fetchAll zetten (tenzij bij een database) maar gewoon getAll.
 
Ward van der Put
Moderator

Ward van der Put

24/11/2013 13:50:25
Quote Anchor link
De constructor kan bij een active record pattern wel een voorbeeld zijn van een methode die meerdere functies heeft.
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 User
{
    public function __construct($id = null)
    {

        if (isset($id)) {
            $this->getById($id);
        }
    }


    private function getById($id)
    {

        // <...>
    }

    private function getByName($name)
    {

        // <...>
    }
}

?>

Nu kun je met new User(1234) de record van een bestaande gebruiker bewerken en met new User() zonder ID vrij letterlijk knutselen een nieuwe gebruiker.

Dus ja, met andere parameters biedt een methode soms andere functionaliteit. Daarvoor zijn parameters immers bedoeld.
Gewijzigd op 24/11/2013 13:50:42 door Ward van der Put
 
Ozzie PHP

Ozzie PHP

24/11/2013 15:14:51
Quote Anchor link
Thanks Ward, goed voorbeeld inderdaad. Maar is dit vergelikjbaar met de situatie zoals ik die schetste?

In jouw voorbeeld geef je een variabele mee aan de constructor en wordt een bepaalde handeling verricht. Geef je geen variabele mee, dan wordt die handeling niet verricht.

In mijn voorbeeld wordt als je een bepaalde variabele meegeeft aan een method een bepaalde handeling verricht, terwijl als je geen variabele meegeeft een andere handeling wordt verricht. Dus de situatie ligt net ietsje anders.

Wat ik nu doe is:

$delete('foo') // verwijder foo
$delete() // geen ID ingegeven, dus verwijder alles

of

$get('foo') // haal foo op
$get() // geen ID ingegeven, dus haal alles op

Mijn vraag is of dit slim is, of dat ik beter gebruik kan maken van deleteAll() en getAll().

Reacties zijn welkom.
 
Remco nvt

Remco nvt

24/11/2013 15:33:22
Quote Anchor link
Lijkt me niet handig als een functie verschillende dingen kan doen afhankelijk van de parameter. In elk geval niet met deze naamgeving.

Want als je dus een typo maakt en die komt door de validatie dan delete je stiekem even alles. Zelfde met de get, op eens krijg je een (waarschijnlijk) array (of een arraycollection object) terug i.p.v het object wat je bedoelde.

Zou de code ook zo schrijven dat mocht er iemand anders ooit mee moet werken de persoon niet voor 'grapjes' komt te staan als een lege tabel opeens.
 
Ward van der Put
Moderator

Ward van der Put

24/11/2013 15:41:54
Quote Anchor link
Een delete() die alle betandden verwijdert zonder parameter, is inderdaad een nogal extreem voorbeeld van hoe het niet moet. Zo'n functie wil je niet schrijven.

Maar meer in het algemeen: parameters in een methode/functie bepalen niet alleen een operand, maar ook de operaties. Kijk bijvoorbeeld maar eens naar iets eenvoudigs maar onmisbaars zoals afronden. Hier hebben we één operand en twee operatoren, waarbij de tweede operator ook nog een constante is:

float round ( float $val [, int $precision = 0 [, int $mode = PHP_ROUND_HALF_UP ]] )

Een minder extreem voorbeeld dan een delete(), maar wel met hetzelfde effect: met $precision kun je even effectief data naar de eeuwige jachtvelden dirigeren.
 
Ozzie PHP

Ozzie PHP

24/11/2013 16:04:54
Quote Anchor link
Ward, ik zou het ook nog via parameters kunnen doen, bijv.

function delete($id, $all = false);

En als je dan $all op true zet, dat ie dan alles verwijdert. De vraag is eigenlijk waar je de grens moet trekken. Moet je 1 delete functie hebben die alles kan verwijderen, van 1 enkele ID tot alle IDs. Of moet je dit onderbrengen in 2 functies delete() en deletAll(). Hetzelfde geldt dan ook voor get() en getAll(). Laat ik de vraag breder trekken. Wanneer is het slim om functies met min of meer dezelfde functionaliteit op te splitsen in meerdere functies?
 
Ward van der Put
Moderator

Ward van der Put

24/11/2013 16:11:47
Quote Anchor link
Ozzie PHP op 24/11/2013 16:04:54:
Laat ik de vraag breder trekken. Wanneer is het slim om functies met min of meer dezelfde functionaliteit op te splitsen in meerdere functies?
Eigenlijk heel eenvoudig: zodra je iets gaat/kunt kopiëren en plakken, heb je duplicaten die hetzelfde doen. Dan kun je beter een gedeelde methode gebruiken. Het is heel gebruikelijk (en vaak beter zelfs) dat methoden andere methoden gebruiken.
 
Ozzie PHP

Ozzie PHP

24/11/2013 16:26:45
Quote Anchor link
In het voorbeeld van delete en deleteAll hoef je niks te kopiëren/plakken dus dat argument gaat in dit geval niet op. Het zouden dus goed 2 functies kunnen zijn.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
<?php

public function delete($id) {
  unset($this->array[$id]);
}


public function deleteAll() {
  unset($this->array);
}


?>

De tegenhanger met 1 functie zou dan zoiets zijn:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
<?php

public function delete($id = null) {
  if (is_null($id)) {
    unset($this->array);
  }
else {
    unset($this->array[$id]);
}


?>

Maar wat is nu de beste oplossing? Zeg je, het gaat in beide gevallen om het verwijderen van data, dus we gebruiken 1 functie (het 2e voorbeeld). Of zeg je, nee het gaat hier weliswaar om het verwijderen van data, maar er zit een verschil tussen het verwijderen van 1 element of in 1x alle data en daarom gebruik je 2 functies (voorbeeld 1). Hoe weet je nu wat de juiste (of betere) manier is? Allebei de manieren zullen werken, maar in 1 van beide manieren handiger/praktischer in gebruik?
 
Ward van der Put
Moderator

Ward van der Put

24/11/2013 16:33:45
Quote Anchor link
Hangt ervan af, zoals vaker. Net verwijderde delete() nog alle bestanden, nu slechts een array.
 
Wouter J

Wouter J

24/11/2013 16:38:38
Quote Anchor link
Ozzie, dit is geheel persoonlijk. Geen van beide is beter, de één kan slechts alleen de voorkeur krijgen van een persoon.

Bijv. jQuery werkt heel erg veel met andere functionaliteiten in dezelfde functie doormiddel van argumenten. Bijv. $('#a').attr('id') verkrijgt de waarde van het id attribuut terwilj $('#a').attr('id', 'f') het attribuut id een waarde meegeeft.
 
Ozzie PHP

Ozzie PHP

24/11/2013 16:43:16
Quote Anchor link
@Ward:

Het is even een code voorbeeldje om te laten zien dat ik geen dubbele code gebruik en het volgens jouw theorie dus 2 functies mogen zijn. Het kan gaan om een array of om bestanden, maar maakt dat iets uit? Het gaat vooral om de gedachte die erachter zit. Moet je alles wat maar enigszins met het verwijderproces te maken heeft in 1 functie stoppen, of verspreid je dit over meerdere functies.

@Wouter:

Oké, thanks. Er is dus geen goed of fout. Wat vind jij zelf handiger? Eén delete functie die zowel één ID (array-key, bestand, database-row of wat dan ook) kan verwijderen als alle IDs (op het moment dat je geen ID meegeeft). Of vind jij het persoonlijk beter om 2 functies te gebruiken, een delete() en deleteAll()?
 
Wouter J

Wouter J

24/11/2013 16:53:17
Quote Anchor link
2 functies en dan, mocht je het echt nodig vinden, 1 functie die ze combineert. Bijv:
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
22
<?php

class User
{
    private $name;

    public function getName()
    {

        return $this->name;
    }


    public function setName($this->name);

    public function name($name = null)
    {

        if (null === $name) {
            return $this->getName();
        }


        return $this->setName($name);
    }
}
 
Ozzie PHP

Ozzie PHP

24/11/2013 17:03:03
Quote Anchor link
Grappige constructie, ik denk dat ik het dan maar bij 2 functies ga houden.

Offtopic:

Ik zie dat jij vergelijkt met null via null === $name. Waarom gebruik je niet de is_null() functie?

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
<?php
if (is_null($name)) {
  // ...
}
[
/offtopic]
 
Dos Moonen

Dos Moonen

24/11/2013 17:10:32
Quote Anchor link
Ozzie PHP op 24/11/2013 16:43:16:
Oké, thanks. Er is dus geen goed of fout. Wat vind jij zelf handiger? Eén delete functie die zowel één ID (array-key, bestand, database-row of wat dan ook) kan verwijderen als alle IDs (op het moment dat je geen ID meegeeft). Of vind jij het persoonlijk beter om 2 functies te gebruiken, een delete() en deleteAll()?

Ik stem voor twee methods voor zulke use cases.

Getters & setters wil ik nog wel eens combineren:
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
<?php

public function hash($hash = null)
{

    switch(func_num_args())
    {
        case
0:
            return $this->hash;
        default:

            $this->hash = (string) $hash;
            return $this;
    }
}


?>


Quote:
k zie dat jij vergelijkt met null via null === $name. Waarom gebruik je niet de is_null() functie?

Eerste comment op http://us1.php.net/is_null geeft aan dat het veel sneller is met het zelfde resultaat.
Gewijzigd op 24/11/2013 19:51:51 door Dos Moonen
 
Ozzie PHP

Ozzie PHP

24/11/2013 18:27:53
Quote Anchor link
Ah oké thanks. Ik zal straks eens even benchmarken dan!
 



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.