ugrás a tartalomhoz

Adattípus automatikus konverziójának korlátozása

daniel.p · 2012. Jan. 5. (Cs), 14.59
Sziasztok!

Mostanában ismerkedem a PHP OOP részével és itt bizony, ami korábban jó dolog volt (ti.: gyengén típusosság) most kezd egy kicsit aggályossá válni.

A kérdésem a következő: van-e valamilyen mód arra, hogy egy adott osztály tulajdonságának típusát úgymond "beleégessük" a kódba?

A példa:

class foo {
  // ide stringet várunk
  private $bar;
  
  public function foo() {
    // típus meghatározása
    $this->bar = (string) $this->bar;
    // itt még string a típus
    }
   
  public function output($print) {
    $this->bar = $print;
    print gettype($this->bar).'<br />';
    // output: "double"
    print $this->bar;
    }
}

$foo = new foo();
print $foo->output(5.44);
Magyarul azt szeretném elérni, hogy a konstruktorban megadott string típus maradjon érvényes bármilyen változó értékadásnál és pl. az 5.44-et ne konvertálja automatikusan lebegőpontossá, hanem maradjon string. Ki lehet ezt valahogy kényszeríteni anélkül, hogy minden metódus paraméterére a függvényen belül meghívok egy settype()-ot?

A másik kérdésem: a PHP5 elvileg támogatja kontruktorként a _construct függvényt, ugyanakkor, ha így helyezem el az osztályban, akkor nem hívódik meg normálisan. Van tippetek, hogy ez miért lehet?

Köszönöm.
 
1

Szerintem te megpróbálod

H.Z. v2 · 2012. Jan. 5. (Cs), 15.45
Szerintem te megpróbálod megerőszakolni a PHP-t. A PHP ú.n. gyengén típusos nyelv. A változó típusa attól függ, hogy utoljára mit tettél bele.
Ha egyszer stringet teszel bele, a következő alkalommal meg lebegőpontos értéket, akkor lebegőpontossá válik. Ez így működik.
Annyit tehetsz, hogy azokat a változókat, amiket fix típussal akarsz használni, nem értékadáson keresztül éred el, hanem getter/setter metódusok segítségével és ezek közül valamelyikkel kierőszakolod a megfelelő típust.
(de ha hülyeséget írtam, valaki majd kijavít)


––––––––––––––––––––––––––––––––
A konstruktort __construct-nak hívják, két _ jellel az elején.
2

Yepp, kell csinálni neki

inf3rno · 2012. Jan. 5. (Cs), 15.47
Yepp, kell csinálni neki setter-t, illetve a konstruktorban is setter hívást kell elhelyezni, ha ott is értéket szeretnél beállítani a tulajdonságnak...


class Foo {

    private $bar;

    public function __construct() {
        $this->setBar(1.22);
    }

    public function setBar($bar) {
        $this->bar = (string) $bar;
    }

    public function output() {
        print gettype($this->bar) . '<br />';
        print $this->bar;
    }

}

$foo = new Foo();
$foo->output();

Egyébkéntis setter kell minden olyasminek, amit kívülről állítasz be, vagy több helyről hívsz belülről, és egy szimpla beállításnál több dolgot csinál. Itt mondjuk a típuskonverzióval több egy szimpla értékadásnál... (Azért kell setter ilyenkor is, hogy elkerüld a kódismétlődést...)
3

Igen, kicsit megerőszakolás

daniel.p · 2012. Jan. 5. (Cs), 16.29
Igen, kicsit megerőszakolás lenne, de talán könnyebben tervezhető (és kivitelezhető) lenne egy program, ha nem kellene állandóan típusátalakítást végezni minden értékadás előtt.

Amit te és inf3rno is írtok, az gyakorlatilag ugyanaz, mintha egy metódusnál adott paraméterre meghívom a settype()-ot és így kényszerítem rá, hogy olyan típusú maradjon, amilyennek szánom.

class foo {
  // ide stringet várunk
  private $bar;
      
  private function setStr($name,$val) {
    $this->$name = (string) $val;}  

  private function setInt($name,$val) {
    //..
    }
    
  private function setDbl($name,$val) {
    //..
    }        
   
  public function output($print) {
    $this->setStr('bar',$print);
    print gettype($this->bar).'<br />';
    print $this->bar;}
}

$foo = new foo();
print $foo->output('hello');
A leírásotok alapján kell egy metódus, ami beállítja a típust és egyúttal értéket is ad a változónak. Ráadásul minden típusra külön metódus kell, ami még önmagában nem is lenne gond, csak épp a $this->setStr('bar',$print); majdnem olyan, mintha settype-olnék, azaz éppenséggel nem sok időt takarít meg. Arra viszont valóban jó, hogy nem fog kimaradni a típusátalakítás, mert egyébként értéket sem tudok adni a tulajdonságnak. Hmmm...

Ezek szerint ennél tömörebben és egyszerűbben nem nagyon lehet ezt megoldani, igaz?

A __construct csalóka volt, köszi.
4

Hát amit a kódban írtál az

inf3rno · 2012. Jan. 5. (Cs), 17.18
Hát amit a kódban írtál az teljesen értelmetlen, szerintem nagyon félreértettél valamit, nem típusonként kell egy-egy setter, hanem tulajdonságonként...

A másik, hogy az osztályok nevei mindig nagy betűvel kezdődnek, a harmadik meg, hogy mindegyik metódus public, mert csak úgy lehet unit test-et írni rá. A private-et egyébként sem érdemes használni, mert ha örököltetsz, akkor szórakozhatsz egy csomót az átírásával, jobb a protected helyette meg a final ha nem akarod, hogy örökíthető legyen az osztály. Szerintem jobban teszed, ha először alapvető dolgoknak utánaolvasol és csak utána állsz neki oo programozni.
5

A "mostanában ismerkedem..."

chop · 2012. Jan. 5. (Cs), 18.12
A "mostanában ismerkedem..." konkrétan azt jelenti, hogy tegnap...:)

Nem értettem félre, amit írtál, csak épp nekem sokkal logikusabbnak tűnik, hogy adattípusonként írok egy metódust, ami értéket ad egy tulajdonságnak és egyúttal be is állítja a megfelelő (várt) adattípust. Ha tulajdonságonként kell írni egyet és van mondjuk húsz változód, akkor húsz metódus kell, így meg csak adattípusonként egy. Nem a lustaság miatt mondom, hogy kevesebb, csak épp nem értem, hogy miért kellene tulajdonságonként írni egyet, ha a típusonkénti meghívásukkal is ugyanazt azt eredményt érjük el (átkonvertáljuk a típust és értéket is kap). Miért jobb tulajdonságonként beállítani, mint adattípusonként?

A félreértések elkerülése végett: annyit szeretnék, hogy minden tulajdonság automatikusan a várt adattípusú legyen értékadáskor, így gyakorlatilag egy primív típusellenőrzés is történik. Ezt szerintem az én kódom is tudja.:) Hol van a gebasz?

A private-tel és a kisbetűs kezdéssel kapcsolatban jogos a felvetésed, tudjuk be mindezt a zöldfülűségemnek...:)

(Az előző user vagyok, csak közben megjött a jelszavam a mailcímemre.)
6

Kissé drasztikusan

H.Z. v2 · 2012. Jan. 5. (Cs), 18.31
Kissé drasztikusan fogalmazva: szerintem próbálkozz más nyelvekkel, pl. java, C#! Amit te akarsz, arra a PHP nem igazán alkalmas.
Ha meg PHP-zni akarsz, akkor próbáld elfogadni, hogy ez egy gyengén típusos nyelv, a változónak mindig olyan a típusa, amilyen adatot beleteszel. És még örülj, ha a $v="5.67"; stringet ad és nem numerikus értéket! ;)
9

Ejha, nem gondoltam volna,

chop · 2012. Jan. 6. (P), 00.16
Ejha, nem gondoltam volna, hogy ennyire félreérthető lesz a mondanivalóm.:)

Lényeg a lényeg: ahogy említettem, most ismerkedem csak az OOP-alapú PHP-val, eddig csak "spagettikódokat" gyártottam, ami tudom, gyerekeknek való, de azokra a feladatokra, amikre nekem kellett, teljesen alkalmas volt.

Igazából csupán kíváncsiságból kérdeztem, hogy van-e erre mód, mert ugye a Java és a C sokkal szigorúbb nyelv ilyen szempontból és már létrehozáskor megköveteli, hogy megadjuk a változó típusát. Azt gondoltam (gondolom, javítsatok ki, ha tévedek), hogy ez a két nyelv - fogalmazzunk így - a programnyelvek hierarchiájában a PHP fölött van, azaz igazából azok a jó (jobb) módszerek, amik ezekben a nyelvekben vannak. Az érdekelt volna, hogy bár erőszak lenne, de van-e manuális módszer arra, hogy szigorúbbá tegyem a típusvizsgálatot a PHP-ban. Ennek célja igazából csak annyi lenne, hogy az osztályon kívülről érkező változók (pl. metódus paramétere) mindenképp "jó" típusúak legyenek és így a kód is nehezebben sebezhetővé, biztonságosabbá váljon.

Ha fogalmi vagy egyéb zavaraim lennének, akkor kérlek világosítsatok fel!:)
16

statikus- / dinamikus-, erős- / gyenge- típusosság

Poetro · 2012. Jan. 6. (P), 03.29
a Java és a C sokkal szigorúbb nyelv ilyen szempontból és már létrehozáskor megköveteli, hogy megadjuk a változó típusát. Azt gondoltam (gondolom, javítsatok ki, ha tévedek), hogy ez a két nyelv - fogalmazzunk így - a programnyelvek hierarchiájában a PHP fölött van, azaz igazából azok a jó (jobb) módszerek, amik ezekben a nyelvekben vannak

Szerintem nincsen ilyen hierarchia. Minden nyelvnek megvannak a szépségei és a hibái, és nincs ilyen szintű alá / fölé rendeltség. Valamelyik magasabb szintű nyelv mint a másik de ez csak a géphez való közelségét jellemzi, nem pedig hierarchiát. Ha típusos adatokat szeretnél kezelni, akkor használj olyan nyelvet, ami ez megköveteli, van belőle több tucat. A PHP nem típusos nyelv, és minden ilyen irányú kísérlet a nyelv megerőszakolása. Ezt meg kell szokni, vagy mást kell használni. A biztonságosságot pedig a bejövő adatok ellenőrzésével, konvertálásával és teszteléssel lehet elérni.

Az, hogy melyik a jobb módszer, szintén leginkább egyfajta vallási vita. Minden feladatra a megfelelő eszközt kell használni. Ha neked a Java / C statikus típusossága tetszik, vagy más megközelítése, van rengeteg nyelv, ami ezt tudja. De ha körülnézel, hogy statikus típusos, vagy dinamikus típusos nyelvekhez ért több fejlesztő, akkor láthatod, hogy valamiért a dinamikus típusos nyelvek nyernek. És ez nem csak a PHP érdeme. Ott van még a JavaScript, Python, a Perl, a Ruby, az Erlang stb.

Az dinamikus típusosság azt jelenti, hogy a változó akár milyen típusú lehet, sőt ez futás közben változhat is. A statikus típusosság azt jelenti, hogy a változónak előre meg van határozva a típusa, és attól nem térhet el.
Az erősen típusos nyelvekben a változók típusa meghatározza hogy egymással milyen műveletekre képesek. Azaz ha egy számot és egy stringet össze akarnánk adni erősen típusos nyelvben, akkor hibát kapunk. Ezzel szemben a gyengén típusos nyelvben automatikus típuskonverzió történik ebben az esetben, azaz a vagy a számot, vagy a stringet a másikba konvertálja a kód, majd elvégzi rajtuk a műveletet (az, hogy hogyan működik a típuskonverzió nyelvenként különböző). Egyébként gyengén típusos nyelvből elég kevés van, míg dinamikus típusos nyelvből pedig sok (a PHP mindkettő tulajdonsággal rendelkezik, akárcsak a JavaScript, bár a konvertálás szabályai különböznek).
7

Teszek egy kis kitérőt,

Kubi · 2012. Jan. 5. (Cs), 21.49
Teszek egy kis kitérőt, rámutatva, miért is rossz elgondolás az, hogy tipusonként akarsz getter, setter megoldást csinálni :)

Ha kicsit belemászol még jobban az oop-be, találkozol azzal a logikával, hogy az objektumokon belüli változókat protected tulajdonsággal vesszük fel, és ezekre getter, setter metódusokat használunk.

Ennek a módszernek az az előnye, hogy ha az objektumon belül valamilyen drasztikus változtatást kell csinálni, vagy egy érték lekérdezéséhez-beállításához valamilyen logikát is hozzá kell fűzni, nem változik az objektum interface-e, csak az objektumban kell változtatást végrehajtanod, azon kívül marad minden a régiben. Írok erre egy példát:

van egy classod, ami egy webshop kosarat reprezentál, és a classodban vagy attributom (változó) ami a kosárban lévő termékek árának összességét tárolja.

class cart
{
  var $sumPrice = 0;
}

$cart = new cart();

// ár megadása
$cart->sumPrice = 1000;

// ár lekérdezése
echo $cart->sumPrice;

Tegyük fel, utólag loggolást kell beépítened a rendszerbe, mert a kosár árak nem jól számolódnak ki. Fenti megoldás esetén az összes olyan helyet meg kell keresned a programban, ahol a sumPrice változót használtad. De ha már az elején getter, setter megoldást választod:

class cart
{
  protected $sumPrice = 0;
  
  public function setSumPrice($price)
  {
    log::logIt('sumPrice', $price);
    $this->sumPrice = $price;
  }

  public function getSumPrice()
  {
    
    return $this->sumPrice;
  }
}
Ebben az esetben már sokkal egyszerűbb a dolgod, csak a setSumPrice és getSumPrice eljárásokat kell módosítanod, egy helyen. Az oop egyik lényege, hogy megszüntessük a kódismétlést, a fenti dizájn erre való.

És hogy visszakanyarodjunk az eredetileg feltett problémádhoz:

class cart
{
  protected $sumPrice = 0;
  
  public function setSumPrice($price)
  {
    if(!is_numeric($price))
    {
      throw new Exception('invalid price');
    }

    $this->sumPrice = $price;
  }

  public function getSumPrice()
  {
    
    return $this->sumPrice;
  }
}
így máris vizsgálva van a sumPrice tipusossága. Azért nem is_int, mert sok esetben ($_POST, $_GET -ből jött paramétereknél stb.) a változó tipuse lehet hogy string, de számot tartalmaz, és azért throw new Exception, mert azt el lehet kapni (try catch) és die()-t már sehol sem használ az ember ha oop-ról van szó.

Tömbök és classok esetén használhatod a "type hinting" megoldást:

class Product
{
   ....
}

class cart
{
  public function addProduct(Product $product)
  {
     ....
  }
}
11

Igen, értem most már, valóban

chop · 2012. Jan. 6. (P), 00.40
Igen, értem most már, valóban félreértettem a dolgokat.

Mea culpa.

Köszönöm.
12

Ott kezdődik a dolog, hogyha

inf3rno · 2012. Jan. 6. (P), 00.42
Ott kezdődik a dolog, hogyha 20 példányváltozód van, akkor kezdheted darabolni mondjuk 4-5 felé az osztályodat, mert túl nagy. Sosem lesz ennyid. A setter meg általában arra való, hogy kívülről állítsanak be értéket vele. Ha oo programozol, akkor amit érdemes szem előtt tartani, hogy az objektumok nem mutatják kifele azt, hogy milyen formában tárolják az adatokat. Szóval mondjuk a "bar" sem mutatja, hogy ő most string vagy double.

A legjobb példa erre mondjuk egy 2d-s vektor. Megadhatod descartes koordinátákkal, de megadhatod polárkoordinátákkal is. A kettő átszámolható egymásba, bármikor lekérheted a koordinátákat bármelyik formában, de arról fogalmad sincs, hogy maga az osztály hogyan tárolja, mert kifele nem szabad, hogy ebből bármit is mutasson... Ugyanígy kívülről nem hívhatsz olyat, hogy setStr($property, $value). A másik ami miatt nem hívhatsz, mert amúgy sem túl jó gyakorlat, ha egy metódus nevében típus szerepel.
8

Miért lényeges neked, hogy

Pethical · 2012. Jan. 5. (Cs), 22.54
Miért lényeges neked, hogy milyen típussal tárolja az értéket a php?
Az esetek 99%-ában teljesen mindegy.
10

(Talán) kezdem már kapisgálni

chop · 2012. Jan. 6. (P), 00.27
(Talán) kezdem már kapisgálni a dolgot: ott néztem be az egészet, hogy a tulajdonságokra akartam típusellenőrzést csinálni, hogy ne lehessen az objektumon kívülről rossz típusú inputot megadni. De igazából nem is ez kell nekem, hanem - amit fentebb is írtam - igazából a metódusok paramétereit kell típus alapján vizsgálnom, mert jellemzően ezek az adatok, amik felhasználótól jöhetnek. Jól gondolom?

Egyébiránt elnézést a tudatlanságomért, de tudtommal abból tanul az ember, ha kérdez.:)
13

Nem jól gondolod. Az ilyen

inf3rno · 2012. Jan. 6. (P), 00.54
Nem jól gondolod. Az ilyen ellenőrzéseket közvetlenül a bemenetnél szokták csinálni. Mondjuk csinálsz egy validator osztályt, aminek megadod, hogy milyen típusokat vársz, aztán az ellenőriz. Ha minden okés, akkor lehet felhasználni a dolgokat, amiket a kérésben kaptál, és csak innentől adhatod tovább őket. Ezen kívül még van 1-2 szűrő, amin át kell küldeni őket, pl: adatbázisba küldéskor escapelni kell, stb... A lényeg, hogy az ellenőrzések mindig a bemeneten történnek. Ez azért van így, mert ugyanazt az adatot több osztály is felhasználhatja, több metódus is megkaphatja paraméternek, szóval mindegyikben külön egyesével ellenőrizni kéne. Ha viszont már az elején leellenőrzöd, akkor többet nem kell, így elkerülöd az ezzel kapcsolatos kód duplázódást. A kód duplázódás amit kerülni kell, mert ha többször van meg ugyanaz a kód, akkor nehezen módosítható, és sokkal nagyobb a hibázás esélye 1-1 ilyen módosításnál... Másrészt meg többet dolgozik a fordító is vele, stb... Szóval a dupla kód általában tervezési hibákra utal.
14

Tehát akkor gyakorlatilag az

chop · 2012. Jan. 6. (P), 01.27
Tehát akkor gyakorlatilag az a cél, hogy csak olyan objektumaim legyenek, amelyek egy dolgot csinálnak, egy feladatért (vagy feladatcsoportért) felelősek? Így akkor elvileg a hibakeresés is jóval egyszerűbbé válik, illetve nincs kódismétlés, plusz újrahasznosítható a kód.

Most ez lehet, hogy hülye kérdés lesz, de ha már ennyire szétbontjuk a dolgokat, akkor egy objektum gyakorlatilag egy valamilyen módon összekapcsolódó (pl. célfeladat alapján) függvénycsoport, nemigaz?

Ha már itt tartunk: tudnátok ajánlani valamilyen jó könyvet, ami a szemléletmódot(!) magyarázza el, tehát nem konkrétan egy adott nyelv alapján íródott?

Pl. nekem az sem túl egyértelmű, hogy (ha már a 20 tulajdonságot is érdemes 4-5 osztályba szétszedni) miért jobb dolog az, hogy örököltetjük egyik osztályt a másikba, ahelyett, hogy fejlesztjük a szülőosztály funkcióit? Na, ez valóban egy teljesen más megközelítés, mint amivel eddig találkoztam...:)
15

Alapelvek röviden :)

MadBence · 2012. Jan. 6. (P), 03.23
Az alapelv úgy néz ki dióhéjban, hogy van egy problémánk, és van egy gépünk, ami egy dolgot tud csinálni: "Oldd meg a problémát!", nyilván ilyen okos gépünk nincs, ezért részekre, modulokra bontjuk (amíg az n-dik gép már meg tudja oldani azt az elemi problémát). Ez a dekompozíció. Akkor csináljuk jól a dolgot, ha a modulban az összetartó erő (kohézió) nagy, és a modulok közötti csatolás laza.
Ezeket a nem túl egzakt fogalmakat azért valahogy be lehet sorolni kategóriákba.
A kohézió osztályozása (erősebbtől a gyengéébig): funkcionális (ugyanazt csinálja), szekvenciális (egymás után csinálják, gyártósor szerűen), kommunikációs (ugyanazon az adaton csinálják), procedurális (kb egymás után csinálják), temporális (időbeli kapcsolat van), logikai (valami logika miatt rakjuk őket egy modulba, tipikusan az Util fantázianevű csodák ilyenek) és a leggyengébb nyilván a véletlenszerű.
A csatolás (méretének) osztályozása (lazától az erősig): laza (primitív adatokkal kommunikál), stamp (valami összetett adat, pl objektum), control (valami vezérlést ad át), közös adat (nincs gazdája az adatnak), tartalmi csatolás (gyakorlatilag átírjuk a másik modul kódját).
Akkor persze szót kell arról ejtenünk, hogy mennyit kell tudnia egy modulnak. Azaz a fan-in/out értéke mennyi. A fan-out az általa meghívott modulok száma (ez 7 körül az optimális), fan-in pedig, hogy a modult hányan hívják. Ez utóbbira nincs igazán szabály, de fontos észben tartani.
És ez is csak a felelősség egy dimenziója... Megérne a téma egy hosszabb írást! :)
(Ja és itt még szó nem volt öröklésről, ami a tervezés gyakorlatilag utolsó mozzanata)
17

Tehát akkor gyakorlatilag az

inf3rno · 2012. Jan. 6. (P), 10.14
Tehát akkor gyakorlatilag az a cél, hogy csak olyan objektumaim legyenek, amelyek egy dolgot csinálnak, egy feladatért (vagy feladatcsoportért) felelősek? Így akkor elvileg a hibakeresés is jóval egyszerűbbé válik, illetve nincs kódismétlés, plusz újrahasznosítható a kód.

Most ez lehet, hogy hülye kérdés lesz, de ha már ennyire szétbontjuk a dolgokat, akkor egy objektum gyakorlatilag egy valamilyen módon összekapcsolódó (pl. célfeladat alapján) függvénycsoport, nemigaz?


Ez igaz. Annyi extra van benne, hogy az adatokat, amiken ezek a függvények dolgoznak csak ők látják, mert ezek az adatok bele vannak zárva az objektumba. (Persze nyilván vannak be és kimenetek, ahol lehet állítgatni vagy lekérni őket, attól függően, hogy mire van szükség.)

Ha már itt tartunk: tudnátok ajánlani valamilyen jó könyvet, ami a szemléletmódot(!) magyarázza el, tehát nem konkrétan egy adott nyelv alapján íródott?

Ilyen könyv nem létezik. Mindig kell példákat felhozni ha szemléletmódot magyarázol, és általában ezek a példák egy nyelvre szoktak korlátozódni. Én pl a clean code-ot ajánlom. Én is aszerint dolgozok egy ideje, és jobb úgy fejleszteni, kevesebbet hibázom.

Pl. nekem az sem túl egyértelmű, hogy (ha már a 20 tulajdonságot is érdemes 4-5 osztályba szétszedni) miért jobb dolog az, hogy örököltetjük egyik osztályt a másikba, ahelyett, hogy fejlesztjük a szülőosztály funkcióit? Na, ez valóban egy teljesen más megközelítés, mint amivel eddig találkoztam...:)

Ez megintcsak újrahasznosítás. Képzeld el, hogy van két olyan osztályod, aminek vannak közös részei, de mégsem teljesen ugyanazok. Szerintem logikus, hogy ezeket a közös részeket kiemeled egy absztrakt osztályba, és onnan származtatod mindkettőt. pl: van kutya meg macska osztályod, mindkettő állat, tehát az állatra jellemző metódusaik azonosak, mondjuk mindkettő eszik meg tud mozogni... Fogod és az evés meg a mozgás metódusokat kiemeled egy absztrakt állatt osztályba. Így elkerülöd a kód duplázódást.
18

Típusosság - OOP

Pepita · 2012. Jan. 6. (P), 21.27
Na igen, nekem is ez az egyik problémám a PHP OOP-vel.
T.i. egy objektumon belül szerintem is egy tulajdonságnak egy típusának kell(ene) lennie, ugyanis, ha változik a típusa, akkor az már - szerintem - nem ugyanaz a tulajdonság.
Igaza van Poetronak abban, hogy ha nem tetszik, válassz(unk) másik nyelvet.De.
A PHP az egyik legelterjettebb szerver oldali nyelv.
A gyengén- ill. dinamikusan típusosságnak van egy hátránya: a sebesség. Minden változóeléréskor a php-nek meg kell állapítania az adat pillanatnyi típusát, ez alapján tud dolgozni az adattal. Ez pedig plusz köröket jelent, minden adateléréskor.
Bennem még mindig mocorog a kétely, hogy mennyire érdemes PHP-ben OOP-zni; ehelyett sok esetben inkább egy-egy fv.-t írok akármi.php-be, majd incude() v. require() azt jónapot. Lehet, hogy épp az OOP erőltetése a PHP megerőszakolása?
Nem biztos, hogy igazam van, ez csak egyéni véleményem.
19

T.i. egy objektumon belül

inf3rno · 2012. Jan. 6. (P), 23.14
T.i. egy objektumon belül szerintem is egy tulajdonságnak egy típusának kell(ene) lennie, ugyanis, ha változik a típusa, akkor az már - szerintem - nem ugyanaz a tulajdonság.


Már miért változna a típusa, úgy tárolod le, ahogy akarod, ha meg nagyon kell, hogy egy típus maradjon, akkor ki tudod kényszeríteni. Nekem ez eddig még sosem okozott problémát, mondjuk én nem is sűrűn foglalkoztam típusos nyelvekkel (kivétel java). Nekem az nem tetszik, hogy mondjuk egy számot string-re kell konvertálnom mielőtt hozzáfűzök egy másik stringhez. Plusz egy sor kód minden alkalommal...

Valaki írta még egy másik topicban, hogy php milyen hülye nyelv, hogy a string összefűzést "."-al csinálják és nem "+"-al, mint minden rendes nyelvben, de szerintem ez a megoldás jobb, mert egyértelműsíti, hogy stringekről van szó. Mondjuk a

$a=10;
$b=3;
$c=$a+$b; //13
$d=$a.$b; //"103"
variációk között remekül különbséget lehet tenni.
21

Ez már inkább csak nézőpont kérdése

Pepita · 2012. Jan. 7. (Szo), 00.32
Én meg előzőleg erősen típusos nyelven programoztam. Egy kicsit túlzás a "Plusz egy sor kód minden alkalommal", Delphiben pl. egészet stringgé: inttostr(123) és kész. Ezt simán be tudod tenni a .-ok v. +-ok közé is, ráadásul csak akkor van típusell./átalakítás, amikor Te odaírod - és nem minden alkalommal.
De ez tényleg nézőpont kérdése.

Szerk.:
Itt tényleg fontos, hogy legyen különbség a . és a + közt. Viszont egy típusos(abb) nyelvben lehet mindenütt +. De ez is csak nézőpont.
20

hát nem tudom, oop nélkül én

Kubi · 2012. Jan. 6. (P), 23.59
hát nem tudom, oop nélkül én már nem is állnék neki egy rendes weblapot megcsinálni. több lenne vele a munka.

A gyengén tipusosság pont hogy tökéletes weboldalak készítéséhez, pl.: ott vannak a formok, input mező, számot vársz a felhasználótól, nem kell szórakozni azzal hogy konvertáld a stringet integerré, és nem látom, hogy ez mért lenne összeférhetetlen oop logikájával.

A form validálás már másik tészta, használjon az ember egy jó frameworkot és megcsinálja a dolog 80%-át, csak beállítani kell és az adott form csak megfelelő adatokat tartalmazhat.
22

Hát igen

Pepita · 2012. Jan. 7. (Szo), 00.40
Pont innét a sok dilemmám, u.is amiket írtál, azzal én is bő 90%-ban egyetértek... Azért megjegyezném: sok (kisebb) "rendes weblap" van, amit kár lenne OOP-zni (ugye nem sok értelme van 1+ osztályt csinálni egy olyan dologból, aminek 1 példánya van), pláne még xy framework alatt fejleszteni. Sok esetben ez az ágyúval-a-verébre.
23

Tesztelhetőség szempontjából

inf3rno · 2012. Jan. 7. (Szo), 11.25
Tesztelhetőség szempontjából talán jobb, ha osztályok vannak.
24

Re: Tesztelhetőség szempontjából

kemmma · 2012. Jan. 7. (Szo), 12.36
Egy másik topic-ban pont ezzel kapcsolatban tettem fel néhány kérdést: http://weblabor.hu/cikkek/php-osztalyok-egysegtesztelese#comment-83473

Fontos tesztelni, oké, az osztályok ebben segítenek, oké...

De konkrétan mit is csinálunk?

Van egy osztály, konstruktor függvényében átadunk mindenféle opciót, hogy annak megfelelően készítse el a HTML oldalt. Ezen mit lehet tesztelni? És ez majd miben segít nekünk a későbbiekben?
25

Van egy olyan irányelv, hogy

inf3rno · 2012. Jan. 7. (Szo), 12.57
Van egy olyan irányelv, hogy egy metódus paramétereinek az ideális száma nulla. Szóval ha mindenféle paramétert akarsz átadni constructor injection-nel, az gáz, helyette kapásból setter kéne minden paraméternek...

Ha több paraméter van, akkor többféleképpen lehet elkészíteni a HTML kimenetet, ha többféle kimenet van, akkor el lehet gondolkodni, hogy a közös részt kiemeled egy absztrakt osztályba, és minden kimenet típusnak csinálsz egy-egy osztályt, illetve készítesz egy provider-t, ami kimenet készítő osztályt csinál, a paraméterek alapján, stb...

Szóval itt arról van szó, hogy a kódod akkor átlátható, ha az osztály és metódus nevekből megmondod, hogy mit csinál. Ha van egy függvényed 5 paraméterrel, akkor abból nem biztos, hogy megmondod, hogy milyen esetben mit csinál...

A későbbiekben egyrészt abban segít, hogy hozzászoksz, az átlátható kód írásához meg ha módosítani akarod az aktuális oldalt, akkor nem remélhetőleg olyan kis részekre lesz darabolva, amik között már elég hamar megtalálod azt, amelyiket módosítani akarsz. Fel lehet ezt fogni úgy is, hogy amikor osztályokat és metódusokat csinálsz, akkor térképet csinálsz arról, hogy melyik része hol van a kódnak és mit csinál. Ha jól van megírva a kód, akkor az interface-ekből és az osztálynevekből ki lehet találni, hogy mit csinál.
26

Látom sikerült a lényeget

kemmma · 2012. Jan. 7. (Szo), 15.21
Látom sikerült a lényeget kivenned a kérdésemből... :) Tehát üres konstruktorral és set, get függvények mellett mit vizsgálnál egy ilyen osztálynál? És hogyan?
27

Úgy érted hogy lehet unit

inf3rno · 2012. Jan. 7. (Szo), 17.29
Úgy érted hogy lehet unit test-et tolni egy olyan osztályra, ami HTML-t generál?
Pl megadod neki a paramétereket, aztán megnézed, hogy a kimenet egyezik e azzal, amit vársz. Sima sztring összehasonlítás...

Ha elég kicsi részekre van feldarabolva a kimeneti HTML generálása, akkor egyáltalán nem bonyolult tesztelni. Ami még van unit test-nél az a selenium, az csinál egy dom fát a kimenetről, aztán lehet pl kattintani a gombokra vagy a linkekre benne, stb... Pontosan nem tudom ez milyen szinten van kidolgozva (pl van e javascript támogatottság benne), mert még nem használtam.
28

Úgy! :)

kemmma · 2012. Jan. 8. (V), 10.35
Pepita írta, hogy vannak olyan kis weblapok, amiknél felesleges OOP. Erre írtad, hogy azért érdemes OOP-t használni, mert azzal lehet tesztelni... magam részéről a TDD-vel mostanában ismerkedek... egyelőre inkább csak próbálkozok...
Az MVC minta esetén az modell esetén még csak-csak tudom, hogy mit kellene csinálni... de a nézet részt egyszerűen nem tudom. Sok munka és semmi haszna. (szó szoros értelmében semmi) De mivel mindenhol a TDD előnyeit hallom, ezért valószínűsítem valamit én csinálok rosszul, ezért kérdeztem rá, hogy egy HTML oldalt generáló egyszerű osztálynál mit csinálunk. Miért írtad azt, hogy "Tesztelhetőség szempontjából talán jobb, ha osztályok vannak."? Nulla számolás, nulla aritmetika, nulla logikai függőség, csupán string konkatenálás... mit vizsgálsz itt? És ez miben segít?
29

Ez ilyen meddő elméleti vita,

inf3rno · 2012. Jan. 8. (V), 12.37
Ez ilyen meddő elméleti vita, szerintem nem egyre gondolunk... Ha mutatsz példát megmutatom, hogy szerintem mit lehet javítani rajta (már ha lehet). Nagyon egyszerű oldalaknál nem muszáj OOP-t használni, viszont nagyon egyszerű oldalakhoz szerver oldali nyelv sem feltétlen kell... Nehezen tudok elképzelni olyan oldalt, amiben a szerver oldal csak sztring összefűzéseket csinál, és ezért valaki fizeti a hostingot... (Persze sosem lehet tudni.) Általában szokott lenni bejelentkezés, jogosultság kezelés, adatok tárolása, stb... A HTML generálásnál meg szinte mindig vannak ismétlődő, vagy egymáshoz hasonló részek, amiket osztályokkal könnyen újra lehet hasznosítani, függvényekkel viszont csak nehezen.
30

Meddő vita? :)

kemmma · 2012. Jan. 8. (V), 13.54
A TDD cikknél is, illetve itt is arra szerettem volna példát kapni, hogy a triviálisnak kinéző osztályoknál mit kell tesztelni.

Ez nem meddő vita, mivel én még sehol sem láttam valódi TDD-t működés közben, ezért kaptam az alkalmat és a hozzászólásodra reagáltam. Remélve, hogy kapok konkrét példát.

Ahogy a TDD cikknél is leírtam, nem a TDD-t vitatom, hanem a működésre szeretnék példát kapni.

Belépés, jogosultság és a HTML megjelenítés gondolom nem ugyanannak az osztálynak a feladata, tehát a kérdés még adott, hogy a HTML megjelenítésre használt osztályt lehet-e egyáltalán úgy ellenőrizni, hogy az megfeleljen azon elvárásoknak, amiket a TDD-nél várunk.
31

Persze, hogy lehet, csak nem

inf3rno · 2012. Jan. 8. (V), 14.16
Persze, hogy lehet, csak nem biztos, hogy megéri sztring összefűzéseket tesztelni. A végeredményben általában úgyis látszik, ha valami hiba van... Inkább a bemenetet szűrő kód, a logikai rész meg az adatbázis kérések tesztelésére koncentrálnék a helyedben...

Elméletileg lehet TDD-vel view réteget fejleszteni, ha már van egy kész HTML sablonod, aminél tudod, hogy melyik részekre mit akarsz betenni, és annak milyen a kimeneti HTML kódja... Azt hiszem a behúzások ebbe jó bele tudnak zavarni, gondolom ezt a sztring összehasonlításos problémát seleniummal át lehet valahogy hidalni, és DOM összehasonlítást csinálni, viszont mint már írtam én még nem használtam a seleniumot, szóval nem tudom mire képes... Ami biztos, hogy sztring összehasonlításos módszerrel fix, hogy nem csinálnám, mert macerás... Akkor inkább nem tesztelném a kinézeti részt...
32

Rajtunk kívül követi még valaki?

Pepita · 2012. Jan. 10. (K), 07.47
,viszont nagyon egyszerű oldalakhoz szerver oldali nyelv sem feltétlen kell
Mondjuk legyen egy 8 lapból álló full statikus site, de ki akarod írni a látogatottságot. És semmi mást. Már is kell, de csak ici-pici php és session.
Amíg pl. az oldalhoz tartozik fixen 2, de legfeljebb 10 adminisztrátor (havi 1-2 hírt és képeket feltölteni), és rajtuk kívül csak a regelés nélküli látogatók, én bizony még mysql-t sem használok, hanem szép kis fájlocskákba mentem az adatokat meg azt a pár hírt. És összességében sokkal kevesebbet dolgoztam vele. Igaz, rázósabb, ha módosítani kell, de az ilyen nagyonegyszerűeket általában csak lecserélni kell (ha kell).
33

Ha van egy jó

inf3rno · 2012. Jan. 10. (K), 11.07
Ha van egy jó keretrendszered, akkor szerintem biztosan kevesebbet kell dolgozni rajta, mint ahogy te csinálod. Persze nulláról tényleg több munka megírni mindent. Én mondjuk nem szeretek foglalkozni HTML-el, uh. én layout, stb... osztályokat használnék már a kimenet generálására is, és egy deka HTML-t nem írnék (hacsak nem nagyon muszáj). De ez az én felfogásom :-)
34

Szerintem ejtsük

Pepita · 2012. Jan. 10. (K), 11.42
most már a témát, mert megint visszakanyarodtál a keretrendszeredhez... De hamár így történt: neked melyik a "jó keretrendszer"?
35

Zend fw elég használhatónak

inf3rno · 2012. Jan. 10. (K), 13.41
Zend fw elég használhatónak tűnt, de túl sok ötletem volt ahhoz, hogy hogyan javítsam fel, uh inkább sajátot írok éppen.
36

framework használata mellett

Kubi · 2012. Jan. 10. (K), 14.06
framework használata mellett "lobbizok", semmivel sem nehezebb vagy tart tovább mint statikus weboldalak stb. használata.

egyszerű 8 lapból álló oldal, admin bejelentkezéssel symfony fw-el: beállítom sfDoctrineGuardPlugin, beállítom cms plugin, beállítom a dizájnt és megcsinálom a menüt (cms-ben van rá helper), db generálás autómatikusan, tesztelem, kész. Admin felületen ckeditorral szerkeszthető weboldalakat kapok (kép, fájl feltöltés minden nyalánkság). Mindez kb. 3 óra alatt és bármikor tovább fejleszthető.

Hogy most symfony, vagy zf, vagy akármi más, majdnem mindegy, ha lehet benne plugin-okat létrehozni, amiket újra lehet hasznosítani, az újrahasznosításon van a szó, egyszer szenvedsz vele sokat utána 100x felhasználod.
37

+1Tényleg csak ízlés

inf3rno · 2012. Jan. 10. (K), 14.17
+1
Tényleg csak ízlés kérdése, hogy melyik FW-t használod, bármelyikkel megéri foglalkozni...