ugrás a tartalomhoz

Egyszerű vagy többfunkciós függvények

Max Logan · 2007. Jan. 9. (K), 16.39
Fejlesztés közben egy érdekes kérdés vetődött fel bennem. Van egy függvény ami ellenőrzés hajt végre és egy adatot ad vissza, mely három különböző érték lehet. A függvényt két különböző helyen használom. A három értékből az egyik helyen egy érdekes a másik helyen történő felhasználáskor kapom vissza a másik két érték valamelyikét. Ez utóbbi esetben a két értéken felül célszerű lenne még egy listát is visszakapnom attól függően, hogy melyik értékről is beszélünk a kettő közül amit alapon visszaad a függvény.

Tehát mi a célszerűbb megoldás? Csinálni egy függvényt, ami nem csak ellenőriz és visszad egy értéket, hanem adott esetben egy tömbbel is visszatér. Vagy külön megcsinálni egy függvényben az ellenőrzést és egy másikban a lista lekérést. Ez egész kérdés azon alapul, hogy ha az ellenőrzés során az az eset áll fent, ahol egy listára is szükség van, akkor egyúttal meg tudom oldani a függvényen belül. Viszont a másik két esetben nincsen szükség tömb visszaadására.
 
1

UpDate

Max Logan · 2007. Jan. 9. (K), 16.45
Kicsit gondolkodva túlbonyolítottam az első bekezdést. Tehát az első bekezdés helyett:

A függvény ellenőrzést hajt végre. Két helyen használom a függvényt. Első helyen csak a vizsgálat eredményéből következő érték a fontos, míg a másik helyen az eredménytől függően egy tömböt is célszerű lenne visszadni.
2

Koncepció

janoszen · 2007. Jan. 9. (K), 17.36
Na, ez itt koncepcionális kérdés. Szerintem, az, hogy egy függvény különböző fajta értékekkel tér vissza (string, tömb, stb) és utána switch-case-el szétválasztod, elég öngyilkos merénylet és tervezési hiba.

Én úgy csinálnám, hogy csinálnék egy olyan függvényt, hogy isEgyikBemenet() ami visszatér true-false-al, isMasikBemenet(), stb. és a megfelelő függvényt hívnám meg. Aztán az egészet becsomagolnám egy osztályba.

Ennek több előnye is van. Az egyik, hogy nem bízol többet egy függvényre, mint amennyi feltétlenül szükséges. A másik, hogy skálázhatóbb a dolog, mert ha változik a bemeneteli adatok struktúrája, nem kell a függvényben is és a feldolgozórészben is átírni, hanem csak a függvényben / osztályban.
3

Re

Max Logan · 2007. Jan. 9. (K), 19.29
Nem több bemenet van. Az egész lényege, hogy egy adatbázisban tárolt adat vizsgálata után tér vissza 3 féle állapottal a függvény, tehát nem megoldható TRUE-FALSE kimenettel. Az egyik felhasználásnál csak az állapot a fontos (ettől függően kell alkalmazni bizonyos megszorításokat). A másik helyen pedig állapottól függően vagy egy lista jelenik meg (ezért lenne (talán) célszerű csípőböl visszadni a listát is az állapottal együtt) vagy egy adatbeviteli képernyő, vagy kap egy üzenetet a felhasználó, hogy ma már nincsen ott dolga.

Az osztályos dolog kilőve, mert még nem vágom az OOP-t (de már rajta vagyok a tmán, vettem két könyvet az OOP-ről, csak időm nincs még belemélyedni) ...
4

Nem bonyolult

janoszen · 2007. Jan. 9. (K), 22.38
Adj vissza egy eredmény-osztályt.

Legyen pl ez:

<?php
class EredmenyOsztaly
{
 private $eredmenyTipus = 1;
 private $eredmenyLista;

 function setEredmenyTipus($eredmenytipus)
 {
  $this->eredmenyTipus = $eredmenytipus;
 }

 function getEredmenyTipus()
 {
  return $this->eredmenyTipus;
 }

 function setEredmenyLista($eredmenylista)
 {
  $this->eredmenylista = $eredmenylista;
 }

 function getEredmenyLista()
 {
  if ($this->eredmenyTipus==1)
  {
   return $this->eredmenyLista;
  } else {
   return false;
  }
 }
}
?>
Ezek után ezt csinálod az eredményt előállító függvényben:

<?php
 function valami()
 {
  $t = new EredmenyOsztaly();
  $t->setEredmenyTipus(1);
  $t->setEredmenyLista(array());
  return $t;
 }
?>
Végül így kéred le az eredményeket:

<?php
 $eredmeny = valami();
 if ($eredmeny->getEredmenyTipus() == 1)
 {
  $listavaltozo = $eredmeny->getEredmenyLista();
 } else {
  //Csinálj valami mást.
 }
?>
Avagy szépen be van csomagolva egy osztályba és nem kell azzal foglalkozni, hogyan tárolod el a dolgokat. Ennek a mintájára bátran hozzátehetsz saját függvényeket is.
5

ha meg drága a tömb előállítása,

Táskai Zsolt · 2007. Jan. 10. (Sze), 17.05
akkor legyen két függvény az interfészen, és emeld ki egy/néhány (kívül nem használt) külön függvénybe a közös magot. ha a teljesítmény nem probléma, proclub megoldása a nyerő.
6

A megoldás egyelőre ...

Max Logan · 2007. Jan. 10. (Sze), 17.30
Az OO megoldás bár szép nekem még mindig kényelmetlen a használata. Addig nem akarok OO kódot írni míg nem értem, hogy mit hogyan. Két könyvem van a tmáról, már csak idő kellene a tanuláshoz, ami mostanában nagyon nincs. Szóval OOP egyelőre kilőve. Későbbiekben az egész rendszert majd úgyis OO alapokra akarom helyezni és valószínű ezzel egyidőben AJAX feature-öket is fog kapni az oldal.

Szóval a megoldás az lett, hogy a

 Check_Missing_Report();
függvény lekéri a kérdéses értéket az adatbázisból, csinál egy vizsgálatot és 0, 1 vagy 2 értékkel tér vissza.

Aztán csináltam egy

 getMissing_Report_List();
függvényt, ami pedig meghívásra kerül az előző függvény által visszaadott érték vizsgálatakor, amennyiben 2-es jött vissza.

A két függvény csupán annyiban tér el egymástól, hogy a másodikban a vizsgálat helyett return van, valamint a while ciklusban a számlálás helyett feltölti a tömböt amivel visszatér.
7

Pontosan

janoszen · 2007. Jan. 10. (Sze), 18.18
Igen, OO nélkül így kell megcsinálni, ha jól értem a leírásodat.
12

öngyilkos megoldás

pp · 2007. Jan. 11. (Cs), 08.50
a getMissing_Report függvény háromfajta visszatérési értéke 0,1, és egy tömb a listával.

<?php
$missing_report = getMissing_Report();
if(!is_array($missing_report)){
  //feldolgozzuk a listát
}else{
  switch ($missing_report){
    case 0: // 0
            break;
    case 1: // 0
            break;
  }
}
?>
Ez miért is öngyilkos és tervezési hibás megoldás? (már a feldolgozás ;))

pp
13

öngyilkos megoldás

pp · 2007. Jan. 11. (Cs), 08.50
a getMissing_Report függvény háromfajta visszatérési értéke 0,1, és egy tömb a listával.

<?php
$missing_report = getMissing_Report();
if(!is_array($missing_report)){
  //feldolgozzuk a listát
}else{
  switch ($missing_report){
    case 0: // 0
            break;
    case 1: // 0
            break;
  }
}
?>
Ez miért is öngyilkos és tervezési hibás megoldás? (már a feldolgozás ;))

pp
8

Meghíváskor adj egy paramétert

Jano · 2007. Jan. 10. (Sze), 21.16
Egy megoldas: Legyen még egy plusz paraméter ami megmondja, hogy mit kell visszaadni a függvénynek. Pl returnMode = TRUE_FALSE vagy RESULT_LIST
Ebbol egyik lehet alapertelmezett.
9

Nem jó.

janoszen · 2007. Jan. 10. (Sze), 21.22
Pont nem jó, mert a t. kérdező pont nem tudja, hogy mit vár visszatérési értékként.
10

Jobban mondva ...

Max Logan · 2007. Jan. 10. (Sze), 22.02
... tudom, hogy mit várok. A kérdés arra irányult, hogy melyik a célszerűbb megoldás, amit Jano is írt vagy amit néhány kommenttel feljebb már végső megoldásként írtam.

Tehát az egész kérdésem lényeg az volt, hogy programtervezési szempontból melyik megoldás a célszerűbb. A több egyszerű függvény vagy a nagyobb tudású függvény figyelembe véve azt, az első függvény nem egy összetett függvény lenne, tehát nem egy függvénybe csomagolnék be több független folyamatot, hanem egy algoritmus egyszerre képes elvégezni végülis (a megvalósított) kettő feladatát.

A Jano által írt megoldásnál a függvény a program egyik részén történő felhasználásánál csak 0, 1 vagy 2 értékkel térne vissza, míg a másik felhasználásnál visszatérne a három érték valamelyikével és egy tömbbel. A már kész megoldásban pedig a lista visszaadásást egy újabb függvény végzi.

A második megoldás valósítja meg azt, hogy egy függvény csak annyit csináljon, amennyit éppen kell. Viszont jelen esetben ugye nem két külön algoritmusról van szó az összetett függvény esetében, hanem egy plusz érték visszaadásáról amit ugyanaz a while ciklus állít elő, mint ami a 0, 1 vagy 2 értéket.
11

Ha leírnád pontosan mi ez könnyebb lenne

Jano · 2007. Jan. 10. (Sze), 22.29
Nehéz így vaktában tanácsot adni, én is csak egy lehetséges megoldást adtam hátha az tetszik meg, de nem feltétlenül ez a legjobb.

Ha leírod, hogy pontosan mi a feladat sokkal jobb válaszokat kaphatsz.
14

A feladat

Max Logan · 2007. Jan. 11. (Cs), 11.19
A feladat lényege a következő:

A rendszerbe lépve a user-nek kötelező kitöltenie egy napi jelentést, mielőtt megrendelőt tudna feladni. Ehhez hozzájön még az, hogy nem biztos, hogy minden nap belép, tehát kényszeríteni kell a régebbi ki nem töltött jelentések kitöltésére. Vagyis, amíg visszamenőleg vannak kitöltetlen napi jelentések addig nem tud megrendelőt feladni, az állapotát lekérni stb. Ja igen, ami még fontos, hogy jelentést csak hétköznap kell leadnia.

A feladatot úgy oldottam meg, hogy egy táblában minden user-hez eltárolom az utolsó kitöltött napi jelentés unix timestamp-jét úgy, hogy az időt nullázom (pl. 2007-01-11 00:00:00). Ez a jelentés mentése után történik meg.

Az ellenőrzés pedig úgy megy, hogy lekérem a tárolt timestamp-et és ebből kiindulva vizsgálom meg, hogy van-e kitöltetlen napi jelentés és ha van, akkor csak a mai vagy visszamenőleg is van. A vizsgálatot a tárolt nap után kell kezdeni, mert ugye a tárolt napon biztosan adott le jelentést. Ebből következik, hogy három fajta lehet a függvény visszatérési értéke. 0 ha már nem kell jeletést írni, 1 ha csak az aktuális napi jelentést kell kitölteni, és 2 ha több napra visszamenőleg vannak még kitöltetlen jelentések.

A Check_Missing_Report() függvény a következőképpen néz ki:

<?php

 function Check_Missing_Report()
 {
    $i = 0;
    $one_day  = 60 * 60 * 24;  

    # Az utoljára leadott napi jelentés timestamp-jének lekérése
    $sql_query = mysql_fetch_assoc(mysql_query("SELECT ..."));
    $last_day  = $sql_query["last_report"];  
   
    $today = getdate();
    $today = mktime(0, 0, 0, $today["mon"], $today["mday"], $today["year"]);  

    # A tárolt nap után kezdjük a vizsgálatot, mivel
    # a tárolt napon biztosan adott le jelentést
    $act_day = $last_day + $one_day;

    # Megvizsgáljuk, hogy mely nap(ok)on kell
    # jelentést leadnia a user-nek
    while ( $act_day <= $today )
    {
       if ( isWeekday($act_day) )
       {
          $i++;
       }

       $act_day += $one_day;
    }

    if ( $i == 0 ) { return 0; }
    elseif ( $i == 1 ) { return 1; }
    elseif ( $i > 1 ) { return 2; }
 }

?>
A függvényt két helyen alkalmazom. Az első helyen az a lényeg, hogy kell-e még jelentést írnia, mert ha igen, akkor megrendelő feladás, stb. tiltva van addíg amíg ki nem tölt minden jelentést visszamenőleg. Ebből következően itt csak az állapot a fontos.

A másik alkalmazás pedig a jelentések feladása. Ha már nem kell jelentést írnia, akkor tud feladni rendelést, stb. és kap egy üzenetet, hogy már nem kell jelentést leadnia. Ha még van kitöltetlen jelentése, akkor két eset van. Ha a visszaadott érték 1, akkor megjelentik a napi jelentés form-ja és ki kell neki tölteni. Ha 2 akkor meg kell jeleníteni egy listát, amiben látja, hogy melyik napi jelentések hiányoznak még.

Ezt a listát a getMissing_Report_List() függvény adja vissza:

<?php

 function getMissing_Report_List()
 {
    $one_day  = 60 * 60 * 24; 

    # Az utoljára leadott napi jelentés timestamp-jének lekérése
    $sql_query = mysql_fetch_assoc(mysql_query("SELECT ..."));
    $last_day  = $sql_query["last_report"];  

    $today = getdate();
    $today = mktime(0, 0, 0, $today["mon"], $today["mday"], $today["year"]);  

    # A tárolt nap után kezdjük a vizsgálatot, mivel
    # a tárolt napon biztosan adott le jelentést
    $act_day = $last_day + $one_day;

    # Azon napok listáját állítjuk elő, ahol ki
    # kell töltenie a usernek a napi jelentést
    while ( $act_day <= $today )
    {
       if ( isWeekday($act_day) )
       {
          $list[] = $act_day;
       }
       $act_day += $one_day;
    }
    return $list;
 }

?>
Mint látható a lista az első függvénnyel is előállítható. Erre irányult a kérdésem, hogy jelen esetben mi a célszerűbb: amit végülis én csináltam, tehát két kistudású függvény, csak annyit csinálnak amit kell vagy egy összetett függvény bár két funcionalitással, de egy algoritmussal. A másodiknál az állapot és lista visszaadását pedig úgy tudom elképzelni, hogy egy tömböt ad vissza aminek a 0. eleme az állapot és utána a timestamp-ek.
15

Egyik sem

janoszen · 2007. Jan. 11. (Cs), 12.26
Amint nézem, vannak redundáns részek a kettőben. Én azt csinálnám, hogy a közös részeket kiszedném külön függvényekbe.

Persze, be lehet rakni egy nagy függvénybe is, csak kezdj el azon gondolkozni, hogy fogod-e szeretni karbantartani a saját kódodat később.
16

Re

Max Logan · 2007. Jan. 11. (Cs), 12.58
Abban igazad van, hogy a while ciklus előtti részt ki lehetne tenni egy init függvénybe (ami aztán egy tömbben adja vissza az értékeket). De azt nem értem, hogy mit értesz karbantartási problémán, mert ha egy (nagyobb) függvény van, akkor ugye annyi a változás, hogy a két while ciklus-t össze kell hozni.
17

Tfh változik

janoszen · 2007. Jan. 11. (Cs), 16.26
Tegyük fel, változik az a bizonyos "init" rész. Két helyen kell átírnod, nem egy helyen. Nagyobb a veszélye, hogy kihagysz egyet véletlenül. Mert mondjuk, nem emlékszel rá.

Ilyen módszerrel egy csomó fölösleges munkát csinálsz magadnak.
18

Persze ....

Max Logan · 2007. Jan. 11. (Cs), 17.00
... ebben teljes mértékben igazad van, csak nem volt egyértelmű a mondatod, mert úgy lehet érteni, mintha az összetett függvényre értenéd a karbantartási gondokat. Az init függvényt pedig már megoldottam ...