Na navigaci | Klávesové zkratky

Translate to English… Ins Deutsche übersetzen…

Psát před private a protected podtržítko?

PHP 4 postrádá popisovače přístupnosti proměnných (public, protected, private). Proto přišli programátoři s praktickou pomůckou. Podtržítko připojené před proměnnou představuje příznak private případně protected. Prefixový princip pojmenování přetrval paradoxně podnes. Proč? Používání podtržítek v „pětce“ považuji za překonané.

PHP Poznámka: prezentovat postoje pouze pomocí přináší podstatné problémy, pročež s tím končím.

Protected vs. public

Předně, považovat protected a private za podobné příznaky je pěkná pí…(ok, vážně už s  končím) … je nesmysl. Za příbuzné lze spíš označit viditelnosti public a protected. K oběma totiž můžeme přistupovat z vnějšku. V případě protected členů je to mírně komplikovanější v tom, že musíme vytvořit potomka třídy a člen předeklarovat na public, ale to není překážka.

Už samotný fakt, že protected je možné povýšit na public, dokladuje blízkost těchto viditelností. A je zároveň hlavním argumentem proti jejich prefixování. Kdybychom totiž chráněné (tedy protected) proměnné označovali podtržítkem, tak se ho po předeklarování nezbavíme.

Používat podtržítka u chráněných metod nebo proměnných je přežitek, který může situaci pouze zkomplikovat. Vyhněte se mu.

A co private?

Kdyby PHP mělo podporu pro tzv. property, jako mají objektově vyspělejší jazyky, mělo by prefixování soukromých (tedy private) proměnných velký význam. Za stávající situace ho však pozbývá. A pokud jde o soukromé metody, tady žádný objektivní důvod pro používání podtržítek nevidím.

Naopak, určitou roli může sehrát subjektivní pocit, že podtržítka u privátních členů zlepšují orientaci v kódu. To je sice možné, ale zároveň roste i riziko jejich zapomenutí. Proto používání spíš nedoporučuji, nicméně pokud se pro ně rozhodnete, používejte je důsledně všude.

Komentáře

  1. Mordae http://thirdcms.org/~mordae/ #1

    avatar

    Prefixovat? Jako by nestacilo, ze PHP prefixuje protected cleny „\0*\0“ a private „\0ClassName\0“… Zas to ale umoznuje radne pouzivani __set()/__get() pouze pro pristup zvenci, kdyz je protected promenna definovana.

    Ale jinak je nejake promitani scopu do nazvu asi stejne uhozene, jako madarska konvence.

    před 10 lety | reagoval [12] llook [17] Mordae [17] Mordae
  2. Miloslav Ponkrác #2

    Já naopak podtržítka začínám používat, naučil jsem se to v Pythonu, který privátní členy nemá. A přenáším to pomalu i dál.

    Jaktože nemá PHP property, když se dají tak krásně udělat pomocí __get a __set metody? Už jen proto mají podtržítka význam.

    Mimochodem, třeba takové Ruby taky řídí přístupová práva členů pomocí názvu datových členů.

    Ona nějaká taková konvence může být dost užitečná věc, a když jsou to ta podtržítka, tak proč ne?

    V zásadě dodržuji takové pravidlo, pokud zamýšlím používat datové členy ve třídách i zvenku jako interface, pak privátní členy dostanou podtržítko. Pokud naopak důsledně dodržuji, že zvenku se k třídě smí přistupovat jen přes metody a přes členy, pak nemá smysl se podtržítkem zatěžovat, protože jsou stejně všechna data třídy private, a v opravdu krajním případě protected.

    Takže C++, Java, atd.. – podtržítka nepoužívám, všechna data jsou private.

    Python – podtržítka používám pro data, která nemají mít přístup zvenku.

    PHP – podtržítka používám zcela automaticky, všechna data jsou zásadně private, jen když jsem líný, tak někdy public. Navíc nemám-li žádná data bez podtržítka, mohu si property simulovat bez omezení pomocí __get a __set.

    Mimochodem, za mnoho let programátorské praxe jsem se naučil používat protected jen naprosto minimálně, prakticky vůbec, protože to velmi oslabuje zapouzdřenost třídy a zbytečně si vazbíte program. Lidsky řečeno zvyšujete vnitřní složitost programu, a to je vždycky na houby. Velmi mě potěšilo, když jsem stejná pravidla začal nacházet ohledně protected v knížkách profíků, a uváděli stejný důvod jako já.

    Jinak ale téma nadhozené v článku patří mezi „náboženská“ témata, která není možné rozhodnout, ale dá se flamovat, můžeme si kvůli tomu spáchat nějaké násilí, případně vyhodit v rámci nesouhlasu něco do povětří, ale rozhodnout se to nedá. Ať si každý píše co chce.

    před 10 lety | reagoval [12] llook [17] Mordae
  3. Miloslav Ponkrác #3

    [smazáno] Ale jinak je nejake promitani scopu do nazvu asi stejne uhozene, jako madarska konvence. 

    Naopak. Maďarská konvence je sice blbost, ale promítání scopu do názvu může uštřit velmi mnoho bezesných nocí. Například skutečného ostříleného programátora poznáte mimo jiné tak, že už z názvu proměnné poznáte, že jde o globální proměnnou. Například já takovou proměnnou začnu g_. Stejně tak si takový člověk označí názvem několik dalších případů scope. V C++ se mezi opravdovými profíky ujalo, že datové členy třídy (tedy případ určitého scope) budou končit podtržítkem, Microsoftem totéž dělá jinak, začíne je m_ od slova member.

    Takže jakmile vidím cizí zdroják, který označuje v názvem základní scope strašlivě se mi uleví a v duchu takovému člověku děkuji a žehnám. To je totiž jedna z nejlepších věcí, které mohl udělat.

    před 10 lety | reagoval [14] David Grudl [17] Mordae [23] Radek.
  4. johno http://johno.jsmf.net/ #4

    avatar

    Súhlasím s článkom na 100%. To len aby sa vedelo.

    před 10 lety
  5. error414 http://www.error414.com #5

    avatar

    Jak si se zminil o predeklarovani vlastnosti trid, je ponekud zajimava.

    <?php
    class A{
      private $variable = 'jsem ve tride jedna';
    
      function getVariable1(){
        echo $this->variable;
      }
    }
    class B extends A{
      public $variable = 'jsem ve tride dva';
    
      function getVariable2(){
        echo  $this->variable;
      }
    }
    
    $trida = new B;
    $trida->getVariable1();
    echo '<br>';
    $trida->getVariable2();
    ?>

    jsem ve tride jedna
    jsem ve tride dva

  6. David Grudl http://davidgrudl.com #6

    avatar

    #5 error414, Jenže tohle není předeklarování, ale to je deklarování úplně nové proměnné.

    před 10 lety | reagoval [8] error414
  7. DiGi http://www.qr.cz #7

    Jak tu již bylo psáno – v Pythonu to tak funguje automaticky a nejsou s tím žádné zásadní problémy…
    V zapomínání nevidím žádný problém, CodeInsight editory jsou jak pro Python tak pro PHP (které jsou daleko lepší). Takže pak použití podtržítka ještě zpřehledňuje výpis.

    před 10 lety
  8. error414 http://www.error414.com #8

    avatar

    #6 Davide Grudle, jen takova druha technicka, kdyz v potomku predefinuji clen

    class A {
     protected $a = 'tajne';
    }
    
    class B extends A{
     public $a = 'to znam';
    }

    Tak uz se k hodnote s kterou pracoval parent nedostanu.
    To uz pak ta zmena pristupu nema cenu. Ale tohle uz je fakt rejpani.


    Ty podtrzitka nepouzivam protoze jsem videl pouzivani dvou potrzitek, ale byl jsem pote upozornen na to ze si tvurci php muzou vyspomenout a zavadet magicke metody, ktere nejakou velkou nahodou budou mit stejny nazev jako mnou definovane metody.

  9. anode #9

    avatar

    Řídím se PEAR Coding Standards , které doporučují podtržítko psát u private členů a metod, nikoliv však už u protected. Vzhledem ke zmíněnému je to docela rozumné.
    Mimoto stejný dokument doporučuje psát jména globálních proměnných (když už nějaké jsou) kapitálkami.
    Podle mě tato a mnohá další doporučení jsou velice přínosná pro rychlou orientaci v kódu.

    před 10 lety
  10. Miloslav Ponkrác #10

    dgx: Já myslím, že se tu mluvilo o podtržítku na začátku názvu, ne o dvou. Je jasné, že identifikátory začínající dvěma podtržítky si vyhrazují do svého jmenného prostoru autoři PHP na magické metody. Ale jedno podtržítko používat můžeš.

    To už rovnou můžeš argumentovat tím, že se nechceš oženit, protože by si dvě ženy a dvě tchýně nezvládnul. Nezdvojuj automaticky to o čem se mluví :-)

    před 10 lety | reagoval [11] error414
  11. error414 http://www.error414.com #11

    avatar

    #10 Miloslave Ponkráci, to o tech dvouch sem psal ja ne David

    před 10 lety
  12. llook http://llook.wz.cz/weblog/ #12

    avatar

    Ve čtyřce automaticky podtržítko používám, v pětce ne. Pro orientaci v kódu je přehlednější podtržítko před názvem než „@access private“ kdesi v docbloku, ale rozdíl mezi „function _neco()“ a „private function neco()“ už tak znatelný neni.

    Pokud je třída už tak velká, že se nelze vyznat v jejích metodách, pak něco smrdí a je nejspíš potřeba menší refaktoring.

    #2 Miloslave Ponkráci, Náboženského tématu se dotkl spíše #1 Mordae. Jen počkejte, až se objeví nějaký příznivec té úchylné konvence.

    před 10 lety | reagoval [17] Mordae
  13. pete http://pmatous.net/ #13

    psát u „neveřejnejch“ metod/vlastností podtržítko v době, kdy kdejakej editor má autocomplete včetně „nápovědy“ (odkud metoda je, viditelnost, parametry), nebo různý „inspektory“ se mi zdá jako zbytečnost (totéž si myslím o kapitálkách u konstant).

    hojně ho ale využívám u objektů, jejichž vlastnosti obsluhuju výhradně přes overloading (kdy má objekt jednu vlastnost – $_properties, asociativní pole) abych se vyhnul případnýmu konfliktu názvů, resp. pokusu o přístup k valstnoti, která neni veřejná.

    občas ho taky použiju, když vim, že budu určitej objekt dědit víckrát (base → a → b → c) k označení, že daná metoda pochází z objektu, kterej je v hierarchií nejvejš (base).

    před 10 lety | reagoval [14] David Grudl [17] Mordae [25] Štěpán
  14. David Grudl http://davidgrudl.com #14

    avatar

    #8 error414, tady jde o tutéž proměnnou, takže se k ní nejen dostaneš, ty prostě s ní pracuješ stále.

    #13 pete, pokud používáš podtržítka jen občas, děláš si v tom zbytečně guláš. Přece je jedno, ze které úrovně proměnná pochází. Jde o její viditelnost.

    #3 Miloslave Ponkráci,

    promítání scopu do názvu může uštřit velmi mnoho bezesných nocí.

    I při nejlepší vůli si nedovedu představit proč. Připomínám, že se bavíme o jazyce PHP.

    před 10 lety | reagoval [16] pete
  15. Mirek #15

    Podtrzitka pouzivam, pripada mi to citelnejsi. A ted otazka: K cemu je predeklarovani protected na public dobre? Dik.

    před 10 lety | reagoval [26] Mirek
  16. pete http://pmatous.net/ #16

    #14 Davide Grudle, u dědění to používám u metod, u proměnných ne. příklad: rozkládám url a podle ní volám určitej controller, kterej je potomkem „systémovýho“ controlleru (nebo někoho jinýho, ale vždycky to skonči u „systémovýho“, kterje je abstraktní a nese v sobě několik abstraktních metod, který musí každej controller mít), ve kterym jsou metody jako např. přesměrování, nebo forwarding. abych je nějakym způsobem „oddělil“ nebo a aby bylo na první pohled jasný, že je to „systémová“ metoda (i kdesi hluboko v hierarchii controllerů), použiju podtržítko.

    → chtěl jsem tim říct, že podtržítko se dá využít „praktičtějším“ způsobem, než pro neveřejný vlastnosti, zvlášť když to slovo určující viditelnost neni zas tak daleko, anebo když jí chci použít, tak mi ji autocomplete nabídne i s informací o její viditelnosti.

    před 10 lety
  17. Mordae http://thirdcms.org/~mordae/ #17

    avatar

    Predesilam: mluvim o PHP/5.1.

    #2 Miloslave Ponkráci,

    Jaktože nemá PHP property, když se dají tak krásně udělat pomocí __get a __set metody? Už jen proto mají podtržítka význam.

    Jenze PHP automaticky zaridi (pomoci dost drsneho prefixu viz. #1 Mordae), ze protected/private cleny nebudou pouzity, pokud je __{get,set}() definovana a clen je volan zvenci. Takze podtrzitko je zde nanic a konflikt nehrozi. Ten by nastal jen a pouze v pripade, ze by trida definovala clen jako public (tady si nejsem 100% jist). Zkuste si ve tride definovat vsechny tri typy a pretypovat objekt na array. Pak str_replace(„\0“, ‚\0‘, $key) vsechny klice a var_dump() :].

    #3 Miloslave Ponkráci,

    Naopak. Maďarská konvence je sice blbost, ale promítání scopu do názvu může uštřit velmi mnoho bezesných nocí.

    Ano je, http://pantransit.reptiles.org/…ngStyle.html Chapter 3: Naming. Globalni promenne jsou v objektovych jazycich (a PHP) zbytecne. Pokud je potrebujete, zamyslete se nad vytvorenim singletonu, protoze ho vyuzijete stejnym zpusobem a nazasvinite namespace. Navic se pak jako trida lepe dokumentuje.

    #8 error414, Viz #1 Mordae, je to jina promenna, pristup k ni je mozny: $me = (array) $this; return $me["\0*\0variable"], ale to jen na okraj.

    #12 llooku, Uprimne receno, pokud bych se nekdy nedej boze dostal k programku pod wokny, byl bych madar, ale do te doby souhlasim s lidmi, co delani linux kernel, tak nejak jim verim, ze nejsou neschopni. :]

    #13 pete, Kapitalky u konstant jsou zvyk ze starsich jazyku, hojne uzivane v C a vsude mozne jako nazvy maker. Je to zvlastni, ale kazdemu, koho znam pripadaji jako samozrejmost. Me tak vyhovuji take, ale je to asi dost subjektivni. V PHP se da vzdy poznat, ze jde o konstantu, tak neni moc proc to resit.

    Sakra, ja chci nekoho, kdo by mi helpnul s malinkatym PHP projektikem, nemate nekdo 4 hodky casu denne a chut blbnout s PHP? Linux/cygwin PHP/5.1 vyhodou…

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

    avatar

    #17 Mordae, ad #8 error414, to není jiná proměnná, ale tatáž, se změněnou viditelností. Nepatřil spíš komentář k #5 error414? Tam to samozřejmě jiná proměnná je.

    před 10 lety | reagoval [19] Mordae
  19. Mordae http://thirdcms.org/~mordae/ #19

    avatar

    #18 Davide Grudle,

    <?php
    
    class A
    {
            private $var = 'foo';
    }
    
    class B extends A
    {
            public $var = 'bar';
    }
    
    $b = new B();
    $arr = array ( );
    foreach ( (array) $b as $n => $v )
    {
            $arr[str_replace("\0", '\0', $n)] = $v;
    }
    
    var_dump($arr);
    
    ?>
    vystup:
    array(2) {
      ["var"]=>
      string(3) "bar"
      ["\0A\0var"]=>
      string(3) "foo"
    }

    Pokud ovsem zamenime private za protected, "\0*\0var" je odstranena a misto ni je definovana "var";

    array(1) {
      ["var"]=>
      string(3) "bar"
    }

    Je to dano tim, ze puvodni promenna musi byt zachovana. Proto je take soucasti jejiho nazvu i nazev puvodni tridy. Takze se omlouvam. :]

    Shrnuto: protected je definovany per-class a neni nutne v dcerinne tride brat ohled na private promenne potencialne definovane v materske tride, protoze v ni maji vzdy prednost a neni moznost je prepsat. Stejne tak neni zapotrebi brat ohled na private/protected promenne pri pretezovani, protoze __{set,get}() se vola vzdy, kdyz neni pozadovany clen public/definovany.

    Predefinovani protected jako public nahradi puvodni promennou a metody materske tridy pouzivaji ji, protoze protected nenese informaci o tride, ve ktere byla definovana, stejne jako public.

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

    avatar

    #19 Mordae,

    Stejne tak neni zapotrebi brat ohled na private/protected promenne pri pretezovani, protoze __{set,get}() se vola vzdy, kdyz neni pozadovany clen public/definovany.

    Upřesním to: __get/__set se volá tehdy, pokud není definovaná žádná viditelná proměnná. Tedy při užití v rámci třídy má přednost existující private/protected před voláním __get/__set.

    před 10 lety
  21. error414 http://www.error414.com #21

    avatar

    tim prikladem #5 error414 jsem chtel rict ze kdyz definuji funkci ktera pracuje s promenou private definovanou v tride A, potom tridu A podedim a definuji si novou promenou se stejnym jmenem.

    Potom metoda definovana v tride A pristupuje k te private promene ve tride A.

    Je to dost krkolomne receno. Po vysvetleni #19 Mordae je to logicke chovani, ale stejne se me zda ze to muze zanaset spatne odhalitelne chyby.

    A pokud to chapu #8 error414 tak $a je porad stejna jen se prepise defaultni hodnota deklarovana v trida A.

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

    avatar

    #21 error414, ber to tak, že žádná třída nemůže (nemá) používat proměnné, které bude definovat teprve její potomek. Tedy metody ve třídě A zcela v pořádku pracují s vlastními private proměnnými a vůbec je nezajímá, že v nějakém potomkovi bude pod stejným názvem jiná proměnná – to už není jejich věc.

    A stejně tak potomek třídy A – používá si svoje proměnné a také zděděné public/protected proměnné a že pod stejným názvem byla v rodičovské třídě nějaká privátní proměnná ho vůbec nezajímá. Ani se to nemá jak dozvědět.

    před 10 lety | reagoval [24] johno
  23. Radek. #23

    #3 Miloslave Ponkráci, IMHO, opravdový profík globální proměnné nepoužívá VŮBEC.

    před 10 lety
  24. johno http://johno.jsmf.net/ #24

    avatar

    ber to tak, že žádná třída nemůže (nemá) používat proměnné, které bude definovat teprve její potomek.

    #22 Davide Grudle, Pravdu povediac ja mám jedno miestečko, kde to používam celkom rád. Trieda Node definuje premenné, ktoré naplní rodičovská trieda Asset v konštruktore.

    před 10 lety
  25. Štěpán #25

    avatar

    #13 pete,

    …jinak je nejake promitani scopu do nazvu asi stejne uhozene, jako…

    uzbekistánská konvence :@

    Co s tím podtržítkem jako zlepšíte? Osobně jsem přístup s podtržítkem zkoušel a nezdálo se mi, že by to vedlo k nějaké větší přehlednosti spíše naopak…

    před 10 lety
  26. Mirek #26

    #15 Mirku, Me to vazne zajma, mam u toho pocit, ze je to neco, co by se nemelo, ale nevim proc. Prakticky jsem se s tim skoro nesetkal, jen jednou jsem o tom uvazoval (pochopitelne jako: public function moje () { $this->_moje(); }), ale nakonec to nebylo treba.

    před 10 lety

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