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é.
Poznámka: prezentovat postoje pouze pomocí pé 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 pé 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
Mordae #1
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.
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.
Miloslav Ponkrác #3
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.
johno #4
Súhlasím s článkom na 100%. To len aby sa vedelo.
error414 #5
Jak si se zminil o predeklarovani vlastnosti trid, je ponekud zajimava.
jsem ve tride jedna
jsem ve tride dva
David Grudl #6
#5 error414, Jenže tohle není předeklarování, ale to je deklarování úplně nové proměnné.
DiGi #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.
error414 #8
#6 Davide Grudle, jen takova druha technicka, kdyz v potomku predefinuji clen
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.
anode #9
Ří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.
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í 🙂
error414 #11
#10 Miloslave Ponkráci, to o tech dvouch sem psal ja ne David
llook #12
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.
pete #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).
David Grudl #14
#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,
I při nejlepší vůli si nedovedu představit proč. Připomínám, že se bavíme o jazyce PHP.
Mirek #15
Podtrzitka pouzivam, pripada mi to citelnejsi. A ted otazka: K cemu je predeklarovani protected na public dobre? Dik.
pete #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.
Mordae #17
Predesilam: mluvim o PHP/5.1.
#2 Miloslave Ponkráci,
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,
Ano je, https://web.archive.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…
David Grudl #18
#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.
Mordae #19
#18 Davide Grudle,
Pokud ovsem zamenime
private
zaprotected
,"\0*\0var"
je odstranena a misto ni je definovana"var"
;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.
David Grudl #20
#19 Mordae,
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
.error414 #21
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.
David Grudl #22
#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.
Radek. #23
#3 Miloslave Ponkráci, IMHO, opravdový profík globální proměnné nepoužívá VŮBEC.
johno #24
#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.
Štěpán #25
#13 pete,
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…
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.
Tento článek byl uzavřen. Už není možné k němu přidávat komentáře.