Na navigaci | Klávesové zkratky

Translate to English… Ins Deutsche übersetzen…

Nette\Object – taťka všech objektů

Je známo, že objekty se do jazyka PHP dostaly spíš jako nezvaní hosté. Docela příznačným rozdílem mezi jazykem, který byl jako objektový již navrhován, a jazykem, který se jím stal k velkému překvapení samotných tvůrců, je v absenci resp. přítomnosti společného předka všech tříd. Object Pascal deklaruje TObject, DOT.NET má System.Object a v Javě nebo Ruby stojí v hierarchii nejvýše Object (je delikátní, že nejzákladnější třída bývá pojmenována objekt). V PHP nic takového neexistuje.

Základní třída obvykle deklaruje metody pro sebereflexi. Například metodu vracející název třídy. Je to sice detail, ale vždycky mi připadalo tuze ošklivé mixovat hezký objektový kód s voláním pro-objektové funkce get_class:

$a = $obj->myMethod();
$class = $obj->getClass(); // hezké
$class = get_class($obj); // ošklivé
Upozornění: Knihovna se neustále vyvíjí, aktuální informace najdete na webu Nette Framework.

Nekonzistentní generování chyb

Teď trošku odbočím. Objektový model a vůbec chování jazyka PHP mi v mnoha směrech nevyhovuje. Třeba takový přístup k nedeklarovaným členům. To je téměř vždy známka vážné chyby v programu, způsobené třeba překlepem v kódu. Jenže PHP na ni reaguje značně nekonzistentně:

$obj->undeclared = 1; // projde bez hlášení
echo $obj->undeclared2; // generuje Notice
MyClass::$undeclared = 1; // generuje Fatal error
$obj->undeclared(); // generuje Fatal error

Což potvrzuje názor, že chyby úrovně Notice patří k těm nejdůležitějším a nesmí se při ladění vypínat. Druhým extrémem je Fatal error, který by se spíš měl jmenovat Fatal disaster. Proč? Protože jej nelze obsloužit uživatelským skriptem. Nemáme možnost vygenerovat zprávu pro uživatele. Ten zírá na prázdnou stránku a netuší, co se děje. A hlavně, PHP nemá ani tolik slušnosti, aby odeslalo HTTP kód 500, takže rozbitou stránku (v nejhorším i s chybovou hláškou) zaindexují vyhledávače. PHP fůůůj!

Velice by se hodilo, kdyby přístup k nedeklarovaným členům vygeneroval výjimku. Takovou, která se nechá probublat až nahoru, kde ji zachytí krizová bariéra a promění v korektní hlášení.

Skvělé „vlastnosti“

Zase odbočím. Termínem property se označují speciální členy tříd, které umožňují pracovat s metodami tak, jako by to byly proměnné. Mám na mysli tzv. gettery a settery:

$obj->caption = 'Hello World';
// přeloží se na $obj->setCaption('Hello World')

echo $obj->caption;
// přeloží se na volání $obj->getCaption();

To je nesmírně šikovná věc. Zvenku to vypadá jako obyčejná proměnná, ale přístup k ní máme plně pod kontrolou. Můžeme validovat vstupy. Můžeme generovat výstupy, až když jsou skutečně potřeba. A navíc, pokud neexistuje setter, tak máme read-only proměnnou, což nelze u obyčejné proměnné zajistit.

Property podporují všechny moderní objektově orientované jazyky, v PHP však nejsou a na jejich brzkou implementaci bych si ani nesázel.

Extension method

Ještě jednou odbočím. Naposled. Fakt.

Novinkou třetí verze C# jsou extension method. Jedná se o obdobu prototypování, které znáte z JavaScriptu nebo Ruby. Umožňují připsat nové metody do již existující třídy (JavaScript a Ruby dovoluje metody nejen připsat, ale i přepsat, což však považuji za zlo).

K čemu je to dobré? Máme třeba třídu List reprezentující seznam položek, která implementuje metody pro jejich přidávání, rušení a podobně. Z této třídy je odvozena hierarchie podtříd. V praxi zjistíme, že by se nám docela hodila metoda List::shuffle() pro náhodné zamíchání pořadí položek. Jenže kód třídy List nemůžeme modifikovat (je třeba součástí cizí knihovny). Vytvořit potomka, který by zmíněnou metodu měl, také nepomůže, protože bychom museli upravit stávající kód, co objekty List vytváří. A navíc by to neřešilo absenci metod v hierarchii tříd z List odvozených.

Řešením je vytvořit samostatnou funkci, které objekt předáme a ona na něm operaci vykoná. Jen místo $list->suffle() je třeba volat Tools::suffleList($list).

Extension methods jsou rozšíření jazyka, které doplňování metod do tříd na ryze syntaktické úrovni umožní. Můžeme v programu psát $list->suffle() a interpreter bude tiše volat Tools::suffleList($list).

Nette\Object

Po několika odbočkách jsem zpět u diskutované nejvyšší třídy hierarchie. Myslíte, že něco takového PHP potřebuje? S přihlédnutím k celkové koncepci jazyka bych řekl, že ani ne. Ale co kdyby existence této třídy dokázala vyřešit všechny zde zmíněné problémy a rozšířit objektový model jazyka o property a extension method? V tom případě – sem s ní!

Nette\Object je onen zázračný táta všech objektů (dříve NObject). Nenechte se zmást prefixem, nejde o základní třídu jen pro Nette. Používám ji v Texy, dibi a vůbec ve všech svých aplikacích, u tříd, z nichž lze vytvářet objekty.

Samozřejmostí je podpora sebereflexe:

class MyClass extends Object {}
// včetně jmenného prostoru:
// class MyClass extends Nette\Object

$obj = new MyClass();
$class = $obj->getClass();
$has = $obj->getReflection()->hasMethod('test');

Následuje příklad použití vlastností (property):

class Circle extends Object
{
    private $radius;

    public function getRadius()
    {
        return $this->radius;
    }

    public function setRadius($radius)
    {
        // validate value
        $this->radius = max(0, (float) $radius);
    }

    public function getArea()
    {
        return $this->radius * $this->radius * M_PI;
    }
}


$circle = new Circle;
$circle->radius = 12; // as $circle->setRadius(12);

echo "Radius: $circle->radius"; // as $circle->getRadius();
echo "Area: $circle->area";

// but $circle->area = XXX; throws Exception

Technickou stránku implementace jsem se snažil co nejlépe promyslet. Špatně navržená cesta by mohla narušit zapouzdření objektu, mohla by veřejně zpřístupnit protected a private metody a podobně. Toho se v případě Nette\Object obávat nemusíte. Property fungují pouze jako syntactic sugar, jako něco, co může zpřehlednit kód a těšit programátora, ale pokud nechcete, tak to používat nemusíte. Proto platí, že

  • getter i setter musí být veřejná metoda
  • getter je povinný, setter volitelný
  • názvy jsou citlivé na velikost písmen (case-sensitive)

Možná vás napadá, jestli i metody sebereflexe lze volat „oslazené“. Jasně:

echo "Class: $obj->class"; // $obj->getClass();
$has = $obj->reflection->hasMethod('test');

A nakonec extension method:

class MyClass extends Object
{
    public $a;
    public $b;
}


// declare method MyClass::join()
function MyClass_prototype_join(MyClass $_this, $separator)
{
    return $_this->a . $separator . $_this->b;
}

echo $obj->join(' ');

I zde jsem uvažoval nad několika způsoby implementace, nakonec jsem zvolil tento vycházející ze zvyklostí JavaScriptu. Deklarace v podobě globální funkce má tu výhodu, že unikátnost je zaručena přímo jazykem a existenci lze ověřovat klasickými prostředky.

Nette\Object kultivuje jazyk

Používám Nette\Object jako předka všech tříd, protože mi to usnadňuje vývoj (překlep vyhodí výjimku atd). Jde o třídu dostatečně transparentní, neměla by způsobovat žádné kolize, proto ji můžete používat také. Cílem článku bylo především poukázat na vyšší standard a nové možnosti využití knihoven Texy, dibi a (brzy již) Nette.

Download

Komentáře

  1. Lamicz http://citrons.cz #1

    PHP nemá ani tolik slušnosti, aby odeslalo HTTP kód 500…
    Hm, tohle mi zrovna přijde rozumný, protože HTTP stavové kódy vyjadřují stav serveru (třeba Apache) a ne stav scriptovacího jazyka, který je pouze jako doplněk. Tohle je IMHO chyba programátora, ne webového serveru, a to by se mělo rozlišit.

    před 9 lety | reagoval [8] David Grudl [17] pa3k
  2. rarouš http://www.rarous.net #2

    avatar

    To krásný zlo jde napsat i v C# 2+ :D. Stačí jen zvolit vhodný návrh třídy.

    public delegate void VoidMethod();
    
    public class SomeClass {
        public VoidMethod SomeMethod = delegate {
          // něco udělej, ale nespoléhej na to ;)
        };
    }

    PS. nějak to nezvýrazňuje C# kód :(

    před 9 lety
  3. rarouš http://www.rarous.net #3

    avatar

    To hlavní bych zapomněl. Gratuluju k Nette, vypadá to zatím slibně.

    před 9 lety
  4. Jan Tichý http://www.phpguru.cz/ #4

    avatar

    K těm extension methods – možná by se pro úplnost slušelo dodat, že aby takto zvenku dodávané nové metody neporušovaly zapouzdřenost, pak musí ve svém kódu volat výhradně veřejné metody a členské proměnné příslušné třídy. Pokud by nějak sahaly do protected či private metod/členů, tak by již byla zapouzdřenost narušena. V případě NObject je toto principiálně zaručeno, takže tam samozřejmě problém není.

  5. Jan Tichý http://www.phpguru.cz/ #5

    avatar

    #4 Jane Tichý, A ještě jeden důsledek, pokud tedy platí tento předpoklad, pak nepřítomnost extension methods v jazyce nepředstavuje žádný výraznější problém, protože jakákoliv dodatečná funkčnost se pak dá snadno dodat nějakou samostatnou vedle stojící třídou, které se instance původního objektu předá například jako parametr (bůchví, jak se tenhle design pattern jmenuje :)). Mně osobně přijde dokonce toto řešení bližší, protože mám všude jasně odlišeno, co patří původní třídě a co je dodáno zvenku.

    před 9 lety | reagoval [8] David Grudl
  6. Techi http://techi.name #6

    avatar

    Já bych nedělal z PHP něco co není
    To je podobné jako přidat typovou kontrolu pro integer/string atp. Prostě se to neujme…
    Místo fce get_class() můžeš klidně použít třídu ReflectionClass() když ti to příjde víc OOP cool

    To že zavolání neexistující metody způsobí fatal error → no bože, v ne-interpretovaných jazycích by se kód taky ani nepřeložil. Jestli ti to chování tak vadí, můžeš si do skvělý třídy NObject implemetovat __call() který ti bude fatal error obcházet a pro neznámý metody si vyhodíš třeba jenom warning a všichni budeme spokojený :)

    před 9 lety | reagoval [8] David Grudl
  7. kukulich http://citaty.kukulich.net #7

    PHP nemá ani tolik slušnosti, aby odeslalo HTTP kód 500…

    Od PHP 5.2.4 by to mělo být jinak: „Changed error handler to send HTTP 500 instead of blank page on PHP errors.“

    před 9 lety | reagoval [8] David Grudl [39] David Grudl
  8. David Grudl http://davidgrudl.com #8

    avatar

    #1 Lamiczi, ještě jednou opakuju, že programátor nemá příležitost chybový kód nebo hlášku odeslat. Kód také nemá rozlišovat, který modul serveru chybu způsobil, jestli jádro Apache nebo interpretr PHP.

    #4 Jane Tichý, #5 Jan Tichý přesně tak. Opět se jedná o syntactic sugar, tak je tomu i v C#, jehož třetí verze, která s extension method přišla, je s předchozí binárně kompatibilní. Přidal jsem do článku odstavec, aby to bylo srozumitelnější.

    Sám implementaci považuji za takový experiment, uvidíme, jestli to bude užitečné nebo ne. Zatím jsem rozpolcen ;)

    #6 Techi, nejsem si jist, co přesně se mi snažíš rozmluvit, ani co by se „mělo chytnout“, ale slow down ;)

    #7 kukulichu, tak jsem to vyzkoušel v PHP 5.2.5 a ani ťuk: 200 OK :-(

    před 9 lety
  9. v6ak #9

    „rozbitou stránku (v nejhorším i s chybovou hláškou) zaindexují vyhledávače.“
    JJ, CZilla.cz jsem sledoval pomocí Google Alerts a ten mi posílal zásadně chybový hlášky…

    „Nekonzistentní generování chyb“
    JJ, zajímavý je taky toto:
    A_CONSTANT;// E_NOTICE
    PDO::A_CONSTANT;//E_ERROR

    před 9 lety | reagoval [10] David Grudl
  10. David Grudl http://davidgrudl.com #10

    avatar

    #9 v6aku, Jojo. Ba co hůř, „if (A_CONSTANT) { … }“ se vyhodnotí kladně. To je další důvod proč E_NOTICE považovat za nejdůležitější chybové hlášky.

    před 9 lety
  11. v6ak #11

    BTW: nešlo by to přidávání metod obejít takto?:

    // mám třídu pro práci se soubory sb_file a chybí mi metoda doToChar
    // tak vytvořím potomka a přidám si ji
    class v6_file extends sb_file{
    function goToChar($c){…}
    }
    //někde otvírám soubor, vytvářím původní třídu
    $f=new sb_file($inputFile);

    // a někde jinde používám metodu nové třídy
    v6_file::$f->goToChar(„\n“);

    před 9 lety
  12. JackeLee #12

    Ještě by bylo dobrý, kdyby šlo volat $object->getParentClass() namísto get_parent_class($object). Vím, že to stačí vylepšit přidáním:

    final public function getParentClass()
    {
      return get_parent_class($this);
    }
    před 9 lety | reagoval [13] David Grudl
  13. David Grudl http://davidgrudl.com #13

    avatar

    #12 JackeLee, jasně, to by taky šlo přidat. Rozhoduju se podle toho, jak často se funkce používá. get_parent_class v praxi používám spíš výjimečně, tak mi jako objektový přístup dostačuje $obj->getReflection()->getParentClass() (vrací ReflectionClass)

    před 9 lety
  14. Dr.Diesel #14

    společného předka všech tříd. Object Pascal deklaruje TObject, DOT.NET má System.Object a v Javě nebo Ruby stojí v hierarchii nejvýše Object (je delikátní, že nejzákladnější třída bývá pojmenována objekt). V PHP nic takového neexistuje.

    stdClass ?
    http://cz2.php.net/….classes.php

    Termínem property se označují speciální členy tříd, které umožňují pracovat s metodami tak, jako by to byly proměnné. Mám na mysli tzv. gettery a settery:

    Teď tě teda moc nechápu, PHP má gettery a settery už celkem dávno …
    http://cz2.php.net/…p5.magic.php

    __set() , __get()

    $obj->caption = ‚Hello World‘;
    // přeloží se na $obj->setCaption(‚Hello World‘)

    echo $obj->caption;
    // přeloží se na volání $obj->getCaption();

    Tohle mě osobně třeba přijde ujetý. Vezmi si složitější objekt a máš tam hromady těchhle hovadin, kdy máš v principu vesměs stejně pořád ten samý kód. V PHPku teda takhle:

    $obj->caption = ‚Hello World‘;
    // přeloží se na $obj->__set(‚caption‘,‚Hello World‘)

    echo $obj->caption;
    // přeloží se na volání $obj->__get(‚caption‘);

    A k těm extension methods …

    Řešením je vytvořit samostatnou funkci, které objekt předáme a ona na něm operaci vykoná. Jen místo $list->suffle() je třeba volat Tools::suffleList($list).

    Ovšem za předpokladu, ze pracuje s public promennými objektu …

    před 9 lety | reagoval [16] David Grudl
  15. Dr.Diesel #15

    Jo a kde je Nette? Je prosinec :-D

    před 9 lety
  16. David Grudl http://davidgrudl.com #16

    avatar

    #14 Dr.Diesle,

    • stdClass není společný předek všech tříd.
    • magické gettery a settery nejsou totéž, co „property“. Property je možné pomocí magických metod simulovat. A právě to dělá NObject.
    • „…že pracuje s public promennými objektu“ → jistě, jinak by došlo k porušení zapouzdření, viz #4 Jan Tichý
    před 9 lety
  17. pa3k #17

    #1 Lamiczi, navyše php nemusí bežať len ako modul Apache, kde má to odoslanie HTTP kódu význam.

    před 9 lety | reagoval [18] rarouš
  18. rarouš http://www.rarous.net/ #18

    avatar

    #17 pa3ku, že by zkratka měla opět nový význam? Z PHP se nám vyklubalo PHP a teď teď ho chudáka odtřihnem od serveru, tak z něj bude PHP:-D

    před 9 lety | reagoval [19] The Zero
  19. The Zero http://www.thezero.info/ #19

    avatar

    #18 rarouši, První bylo PHP a ne PHP :)

    před 9 lety
  20. finc http://finc.ic.cz #20

    avatar

    No, docela jsem se u toho pobavil :)
    Abych byl uprimny, take jsem sveho casu premyslel nad tim, ze si napisi vlastni „Object“. Jenze, pak jsem od toho upustil, uz jen z duvodu, ze pri napojeni cizich trid, jsem stejne tam, kde jsem byl :)
    Jinak u toho object mi shazi nasleduji:
    Metoda equals, naprosto zasadni vlastnost. Napr. takovou entitu jako napr. „Zamestnanec“ musim umet porovnavat na urovni samotneho objektu.

    Jeste kdyby se dalo nejak vyresit pretypovani aby se dalo pretypovavat a dalo slusne programovat vuci rozhrani.

    Jinak s clanem vcelku souhlasim, krome „Extension method“, to me osobne prijde jako slusna prasarna.
    V Jave treba existuje pro praci s daty kolekce, jejiz hlavni trida je Collection, dale List, atd.
    Pokud chci udelat neco, co neni standardni pro dane rozhrani, resi se to napr tak, ze existuje rohrani (jako pro srovnani prvku podle sveho razeni), ktere je pote pouzito v knihovnich metodach (staticke metody) v tride Collections. Jinymi slovy, pokud chci napr seradit list, tak vytvorim tridu s implementaci srovnani a jako parametr v konstruktoru ji poslu muj list. Cele toto poslu do dane staticke metody, kde se stane to, ze list mam najednou srovnany.
    Jde take o to, ze kdyz zacnu do trid cpat vlastni metody, tak tim muzu pekne nabourat samotne API. Muze se mi totiz jednoduse stat, ze zacnu pouzivat knihovnu, ktere neco chybi. Sam si tam metodu dopisi. Jenze pote vyjde nova verze, kde jiz metoda bude implementovana (s vlastni implementaci) a pote budu docela v p…li. Zejmena pokud metoda nebude uplne ekvivalentni…
    Ale je to nazor od nazoru :)

    před 9 lety | reagoval [23] David Grudl
  21. ivan_d #21

    Co by se stalo (v příkladu radius), kdybych se po nějaké době rozhodl, že budu radius ukládat uvnitř třídy v jiném tvaru (třeba ho v setteru vynásobím dvěma a v getteru vydělím) – vně je vše stejné, ale co metoda getArea()? Zevnitř objektu totiž na atribut radius vidím. Znamená to přepis getArea()?

    Je to v tomto případě trochu přitažené za vlasy, ale zanevřel jsem na properties, když jsem na toto narazil (kdybych si jen vzpoměl kde). Řeší to NObject?

    před 9 lety | reagoval [23] David Grudl
  22. koubel http://mirin.cz #22

    avatar

    Vytvářet takovouto základní třídu je určité z Tvého pohledu OK, nicméně to pak určitým způsobem svazuje všechny komponenty k sobě až moc prostřednictvím NObject, bez něj pak nejede nic.

    Při extendovani jakychkoli tříd si pak člověk musí si dávat pozor na spoustu věcí, zejména na implementaci magic method. Tím v podstatě nutíš styl práce s objekty potenciálním vývojářům a to některé může odradit.

    Properties se dost špatně dokumentují, ne všechny vývojové
    nástroje s nimy umí pracovat tak dobře jako s getry a setry.

    Další věc je výkonost, magic metody mají opravdu velkou režii v Zend Engine, proto by to chtělo NObject a NClass
    mít v céčku :-).

    před 9 lety | reagoval [23] David Grudl
  23. David Grudl http://davidgrudl.com #23

    avatar

    #20 finci, s tím vlastně zcela souhlasím. Metody Equals a getHashCode jsem tam dokonce chvíli měl, pak zrušil, možná je opět vrátím, ukáže praxe.

    #21 ivan_de, V tomto právě spočívá výhoda properties. Kdyby $radius byla veřejná proměnná a ty ses rozhodl změnit její tvar, byl by to velký problém, bylo by třeba změnit věškerý kód, který objekt a proměnnou používá. Naopak s použitím property měníš pouze vnitřní implementaci.

    #22 kouble, NObject je základní třída pro mé vlastní třídy, jestli ji bude chtít někdo taky tak používat, jeho věc. Jejím smyslem je

    • kultivovat fatal error
    • nabídnout alternativu (ke get_class, k volání $obj->getRadius()…)

    Nabídnout alternativu neznamená někoho do alternativy nutit.

    před 9 lety | reagoval [24] ivan_d
  24. ivan_d #24

    #23 Davide Grudle, Já to právě vidím trochu jako nevýhodu – několikrát jsem zbytečně hledal chybu kvůli opomenutí změnit volání uvnitř třídy. A tak jsem na properties zanevřel. Používám setCosi getCosi, popřípadě zautomatizované přes __call (abych nemusel tupě psát ten nejtriviálněší případ), a mám konvenci – uvnitř tříd si k členským proměným přistupuji přes set/get. Má to i výhodu, že lze (imho elegantně) psát:
    `$neco
    ->setCosi($cosi)
    ->setCosiJineho($cosiJineho)
    ->save();
    `

    před 9 lety | reagoval [25] David Grudl
  25. David Grudl http://davidgrudl.com #25

    avatar

    #24 ivan_de, Rozdíl mezi používám properties a metod getAbc() a setAbc() je pouze v syntaxi. Že mohu místo $obj->setAbc($val) napsat $obj->abc = $val.

    Vezmu to obecněji. Objekt by nikdy neměl vystavovat své atributy veřejně. Jednak tím porušuje princip zapouzdření, odhaluje implementační detaily a může dojít k jeho nekonzistenci. Tak praví koncept OOP.

    Mohlo by se zdát, že veřejné gettery a settery jsou v podstatě jen kompromisem: dál dochází k expozici vznitřní implementace, jen je chráněna konzistence objektu.

    Takový předpoklad by platil, pokud by setter a getter představoval pouhý obal nad privátním atributem. Tak tomu ale není. Výhoda metod typu getAbc() a setAbc($val) je v jejich ustálené konvenci, mají stručný název a zřejmou funkci. Jako třeba v případě konvence názvů metod isXyz() nebo hasXyz($val). A vůbec není podstatné, jestli operují s privátním atributem $abc, takový atribut nemusí ani existovat.

    V kvalitním objektovém kódu tedy (elegantní) syntaxi pro přístup k aktributům můžeme používat pouze uvnitř objektů. Což je škoda, jazyk nabízí něco, co pak většinou nelze použít. No a to je právě příležitost si život trošku odladit špetkou syntaktického cukříku. Myšlenka je prostá, co kdybychom všechny volání $obj->setAbc($val) mohli zapisovat také jako $obj->abc = $val atd?

    V podstatě by bylo hezké, kdyby šlo třeba i $obj->isValid() zapisovat jako $obj->valid?, jenže to v PHP nelze, a především by nešlo o zaběhlou konvencni. Naopak „properties“ zaběhlou konvencí jsou.

    Shrnuto: jde o eleganci zápisu kódu. Na funkci rostlináře to nemá vliv.

    před 9 lety | reagoval [26] ivan_d [31] Michal Aichinger
  26. ivan_d #26

    #25 Davide Grudle, Jo, to je mi jasné, proto jsem se o to svého času snažil, ale popisované problémy vedli k zavržení – v praxi se mi to neosvědčilo (možná svědomitějším programátorům ano). Jen mě napadlo, jestli to není v NObject nějak přečůrané – dříve jsi operoval s $_property, tak mě zajímalo, jestli tam není podobný trik. Ale jsem rád, že budu dál zastávat funkci rostlináře, předsedo.

    před 9 lety
  27. john #27

    to nobjects mě nalákalo stáhnout si texy! a blíže vše prozkoumat… a mám z toho v hlavě jednu takovou mírně intimní otázku na dgx: to všechno stíháš dělat sám nebo máš ješte někoho, kdo ti semtam hilfne? myslím tím třeba ty grafické ikony nebo flashové animace v adresáři „examples“ u texy… že tam zdá se dokonce zbyl čas i na SELECT * FROM girls WHERE ... :-O

    texy teda super!!

    před 9 lety
  28. Dr.Diesel #28

    2 dgx: Neodpoveděls na můj dotaz v posledním postu :-D …

    před 9 lety
  29. v6ak #29

    Já osobně uvažuju, zda do toho jít, ale už to zkouším a vypadá to dobře.

    BTW: je proti konceptu OOP mít jednu vlastnost jako skutečnou vlastnost a druhou emulovanou přes gettery a settery? Nechce se mi psát:

    protected $_aProp;
    
    function setAProp($val){
      $this->_aProp=$val;
    }
    
    function getAProp(){
      return $this->_aProp;
    }

    I když chápu, že někdy to je více nebo méně nutné. (Např. teď jsem psal obal na tokenizer. /* Tam právě zkouším NObject. */)

    Ad konzistence&implementace: Vím, že Zend Framework bývá považován za dobře napsaný, ale toto je fakt hnus:

    $event->sendEventNotifications=new Zend_Gdata_Calendar_Extension_SendEventNotifications('true');

    Navíc právě zde se je problém se zmíněnou konzistencí – stačí napsat logicky vypadající $event->sendEventNotifications=true; a mám: Fatal error: Call to a member function getDOM() on a non-object in …\Zend\Gdata\Calendar\EventEntry.php on line 76

    před 9 lety | reagoval [30] ivan_d
  30. ivan_d #30

    #29 v6aku, ‚je proti konceptu OOP‘ – no někteří správně tvrdí: getters are evil :). OOP to neporušuje – je to jen zpráva, kterou lze zavolat nad objektem. Otázka je (v daném případě), je-li to nejlepší řešení.

    V praxi je imho nutné snažit se minimalizovat CELKOVÝ čas vývoje: CELKOVÝ = současný + (teoretický) budoucí. OOP je jen dobrý postup jak si uspořádat věci, aby ten budoucí čas se nepříjemně nezvyšoval. Samo o sobě není samospásné. Když někdo ‚přežene pravidla OOP a architekturu‘ je to na pytel.

    před 9 lety
  31. Michal Aichinger #31

    #25 Davide Grudle,
    DGX: Rozdíl mezi používám properties a metod getAbc() a setAbc() je pouze v syntaxi. Že mohu místo $obj->setAbc($val) napsat $obj->abc = $val.

    Tak nějak tu zapomínáme na jednu zásadní věc co odlišuje PHP od např. C#. A to je vývojové prostředí. Jelikož C# podporuje properties, tím pádem to podporuje i VS a tím pádem i VS ví jaké typy to vrací a může nabízet pomocí Code Assist metody toho vráceného objektu.

    Tohle v PHP IDEs nelze. Takže pokud používáte např. Prado, které je tímto prolezlé, pak víte, že tam něco je, něco je vám vráceno, ale co to je musíte zjistit buď v paměti, nebo dokumentaci a pak si napsat komentář /*@var $object MyClass*/ , aby vám IDE nabízelo metody objektu. Pokud bude mít zase jen magické nabídne prd.

    Kdo používá IDE, nepotřebuje moc magické metody, protože se většinou nepřepíše do blbého názvu ;-)

    ad ExtensionMethod:
    No v JS a Ruby to má to kouzlo právě proto, že lze modifikovat přes prototype právě tu „třídu“ originální a měnit její chování a ne ji rozšiřovat, to je dost o ničem. Většinou je to tak, že když člověk chce přidat funkčnost (shuffle) tak si to podědí a ve svém kódu to použije poděděný. V cizím kódu se ta poděděná metoda stejně nevyužije. V JS a Ruby má právě kouzlo to, že můžeme ovlivnit i chování těch částí do kterých nemůžeme jinak zasáhnout.

    před 9 lety | reagoval [32] David Grudl
  32. David Grudl http://davidgrudl.com #32

    avatar

    #31 Michale Aichingere, řešením je zatlačit na vývojáře IDE, aby zaimplementovali podporu pro @property (vlastně tímto čtenáře vyzývám – napište jim!). Případně je možné použít tento postup, ale to už s NObject nesouvisí.

    ad extension method: chtěl byste OS, kde by ostatní mohli měnit obsah vašich souborů, ač k nim nemají přístupová práva? Někdo tomu říká kouzelné, já tomu říkám vadné

    před 9 lety | reagoval [34] ivan_d
  33. Petr Staly #33

    Pseudo-objekty v PHP sux, Java/C++ rulez ! :-)

    před 9 lety
  34. ivan_d #34

    #32 Davide Grudle, ‚chtěl byste OS, kde by ostatní mohli měnit obsah vašich souborů, ač k nim nemají přístupová práva?‘ – tak to trochu kulhá – nechtěl bych takový OS, protože někdo jiný by mohl poškodit moje zájmy. Kód nemá svoje zájmy. Ty má pouze programátor. Co může být v 99% případů užitečné vedení, může být v 1% diktát zabedněnce. Ten, kdo užívá můj kód, může být totiž klidně chytřejší než já.

    před 9 lety | reagoval [35] Milan Svoboda
  35. Milan Svoboda #35

    avatar

    #34 ivan_de, To že někdo chytřejší používá můj kód ještě nutně neznamená, že musí přepisovat přímo moje funkce. Protože si pak může stáhnou aplikaci od někoho třetího využívající mého kódu nechá si na webu své upravené knihovny a bude se jen divit, že mu to nefunguje (resp. vetšinou to postihne nějakého zákazníka.). Je to podobný případ jako v javascriptu přpisování prototype. Mně to funguje a že ostatním ne to je jejich problém že :-)

    před 9 lety | reagoval [36] ivan_d
  36. ivan_d #36

    #35 Milane Svobodo, ‚pak může stáhnou aplikaci od někoho třetího využívající mého kódu nechá si na webu své upravené knihovny‘ – kdo to dává dohromady snad ví co dělá a když ne, ať to nedělá. Otázka je, co má člověk ve své kompetenci – zda celek nebo jen část celku, která musí respektovat ostatní. Mluvil jsem o někom chytřejším, ne namyšlenějším.

    Mimochodem proč hned myslet na zásadně jiné chování – změněná metoda může jen obalit původní (a třeba přidat log volání).

    před 9 lety
  37. Washo #37

    avatar

    Muzu se zeptat k cemu slouzi ta getReflection resp. sebereflexe jako takova? Je to pro zjistovani toho jestli lze na danem objektu volat konkretni metodu nebo jeste k necemu?

    Diky.

    před 9 lety | reagoval [38] David Grudl [40] ivan_d
  38. David Grudl http://davidgrudl.com #38

    avatar

    #37 Washo, slouží ke kompletnímu prozkoumání objektu – jaké má metody, jaké mají parametry, ve kterém souboru a na kterém řádku jsou definované a spousta dalších vyčerpávajících informací. Viz Reflection v PHP.

    před 9 lety
  39. David Grudl http://davidgrudl.com #39

    avatar

    #7 kukulichu, tak oprava: PHP 5.2.4 mi už skutečně háže HTTP 500.

    před 9 lety
  40. ivan_d #40

    #37 Washo, Příklad – představ si modifikovaného taťku všech objektů, který bude přes __call poskytovat automaticky ke všem atributům settery a gettery – zjistí si v __call přes Reflection, jestli název metody může odpovídat atributu. Pro prskaly – taťka umožní potomku nadeklarovat konzervativní nebo liberální chováni :)

    class Person extends NObject{
    protected $accessMode = NObject::CONSERVATIVE;

    protected $attrAccess = 'cosi';

    protected $name = '';
    protected $surname = '';
    protected $cosi = '';

    public function __construct($name, $surname){
    $this->name = $name;
    $this->surname = $surname;
    }
    }

    $franc = new Person('Franc', 'Josef');
    $franc->setCosi('cosi');
    $franc->setName('Karl'); #exception

    #nebo

    class Person extends NObject{
    protected $accessMode = NObject::LIBERAL;#default

    protected $name = '';
    protected $surname = '';
    }
    $franc = new Person;
    $franc->setName('Franc')->setSurname('Josef');
    před 9 lety

Tento článek byl uzavřen. Už není možné k němu přidávat komentáře.