Názvoslovný oříšek: jak souhrnně označovat třídy a rozhraní? Jak
třeba nazvat proměnnou, která může obsahovat jak název třídy, tak
rozhraní? Co zvolit místo $class
?
Dá se tomu říkat type ($type
), nicméně to je zase
příliš obecné, protože typem je i řetězec nebo pole. Z pohledu jazyka
jím může být i něco komplikovanějšího, třeba ?array
.
Navíc je sporné, co je v případě objektu jeho typ: je jím název třídy,
nebo je to object
?
Nicméně souhrnné označení pro třídy a rozhraní skutečně existuje: je jím slovo třída.
Cože?
- Z pohledu deklarace je interface hodně ořezaná třída. Může obsahovat jen veřejné abstraktní metody. Což také implikuje nemožnost vytvářet objekty. Rozhraní jsou tedy podmnožinou tříd. A pokud je něco podmnožinou, tak to můžeme označovat názvem nadmnožiny. Člověk je savec, stejně jako rozhraní je třída.
- Nicméně je tady ještě pohled užití. Třída může dědit jen od jedné třídy, ale může implementovat vícero rozhraní. Nicméně tohle je omezení týkající se tříd, samotné rozhraní za to nemůže. Obdobně: třída nemůže dědit od final třídy, ale přitom final třídu pořád vnímáme jako třídu. A také pokud třída může implementovat víc rozhraní (tj. tříd, viz 1.), stále je vnímejme jako třídy.
A co traity? Ty sem vůbec nepatří, z hlediska OOP jednoduše neexistují.
Tedy problém se společným pojmenováním tříd a rozhraní je vyřešen. Říkejme jim prostě třídy.
classes + interfaces = classes
No jo, ale vznikl tady problém nový. Jak říkat třídám, které nejsou rozhraní? Tedy jejich doplňku. Tomu, co se ještě na začátku článku nazývalo třídy. Nerozhraní? Nebo implementations? 🙂
To je ještě větší oříšek. To je pořádný ořech. Víte co, raději zapomeňme na to, že rozhraní jsou také třídy, a tvařme se opět, že každý OOP identifikátor je buď třída, nebo rozhraní. Bude to snazší.
Komentáře
koubel #1
Traity určitě z pohledu OOP existují, jsou to v podstatě interfaces s implementací. IMHO se něco takového jako traity chystají zavést i v C# 8, klasická dědičnost ustupuje do pozadí čím dál častěji, jak se zdá.
Jinak ale smysl postu není moc jasný, protože si nezmínil kontext. Klidně to může být nějaký implementační detail a pak to to můžu pojmenovat jak chci např. „objectTypes“ apod.
Tharos #2
Ty jo, při vší úctě… Interface v „Javovském“ OOP vážně není třída.
Hezky je to vysvětlené například zde.
Očekávat v proměnné pojmenované
$class
název rozhraní by pro mě osobně bylo asi dost WTF…Tomas Votruba #3
Jedu „type“ v autowire stylu „getByType“ :).
Object type by taky šlo, jen to je méně konvenční.
MartinMystikJonas #4
Podle LSP musí podtyp umět vše co nadtyp. Pokud rozhraní neumí vše co třída pak není podtypem třídy, ale naopak. Třída je rozhraní rozšířené o implementaci.
Rozhraní – jakým voláním objekt rozumí
Implementace – jak objekt voláním rozumí
Třída = Rozhraní + implementace
Za mě tedy:
Interfaces = pure interfaces + classes
Tharos #5
Abych byl aspoň trochu konstruktivní, napadá mě ještě:
Vycházím z toho, že rozhraní je kontrakt. Třída, coby implementace, vždy implementuje nějaký kontrakt, ať už nadefinovaný „externě“ (skrze stand-alone interface), anebo nadefinovaný ad-hoc tou třídou. Z každé takové by bylo možné vyextrahovat rozhraní. Pak je tedy
contract
tím společným pojítkem…Hmm, ale jelikož kontrakt je vlastně synonymum pro rozhraní, varianta, o které píše kolega Martin výše, mi dává naprostý smysl. :)
Miloslav Ponkrác #6
Je to jen otázkou terminologie. Class, interface i trait jsou jen různé druhy tříd s rozdílnými možnostmi – z hlediska objektového programování.
Jak Java, tak PHP neuměla konzistentně vyřešit, jak nahlížet na třídy z hlediska vícenásobné dědičnosti – jak konzistentně vyřešit u vícenásobné dědičnosti požadavek na vícenásobné dědění implementací.
Takže se udělala třída, kterých je možné podědit několik a nazvala se rozhraním (interface). A pak se udělal třída, která smí nést implementaci, ale nesmí se podědit vícekrát a nazvala se třídou (class). A pak se navíc v PHP udělala třída, která může nést implementaci, může se dokonce vícekrát podědit, ale typově se projevuje omezeně a nazvala se v PHP trait, ve funkcionálních jazycích se nazývá běžně mixinou (mixin).
Takže jsou to všechno třídy – jen různě očesané svými možnostmi, protože PHP nedokázalo lépe a konzistentněji zvládnou vícenásobnou dědičnost (stejně jako to nedokázala zmiňovaná Java).
Takže třída nutně (podle OOP paradigmatu) nemusí zakládat typovou informaci. Stejně tak jako třída (class) není „rozhraní rozšířené o implemetanci“, protože není možné podědit více classes v jednom potomkovi, ale je možné podědit více interfaces.
Takže skutečně class, interface a traits jsou všechno třídy. S různými možnostmi.
Miloslav Ponkrác
David Grudl #7
#3 Tomas Votruba, Nicméně poměrně často se to, díky nejasnému názvoslovní, děje, třeba i v dokumentaci (viz
$class_name
).#4 MartinMystikJonas, Moc ti nerozumím, s větou „Třída = Rozhraní + implementace“ jsme za jedno, ale jak si z toho (tj. z „class = inteface + implementation“) vyvodil „Interfaces = pure interfaces + classes“ už nechápu. Redefinuješ pojem interface?
MartinMystikJonas #8
#7 David Grudl, Chápu to takhle:
Tak pokud hledám označení pro proměnou obsahující prvek jednoho nebo druhého typu tak to co tato proměnná vlastně označuje je rozhraní tohoto prvku. Proto bych to proměnou nazval interface ať už obsahuje pure interface (tedy interface ve smyslu klíčového slova jazyka) nebo rozhraní třídy (tedy interface definované společně s implementací).
Jednoduše průnik vlastností class a interface je to že definují rozhraní (interface) nějakého objektu. Beru to z pohledu toho jak taková proměnná pak jde použít – jde použít v místech, kde podle ní potřebuju třeba určit jakým voláním to co obsahuje bude rozumět.
MartinMystikJonas #9
Možné ještě pro přehlednost, ať ujasníme pojmy:
INTERFACE – klíčové slovo jazyka, definice rozhraní objektu bez implementace
CLASS – klíčové slovo jakzyka, definice rozhraní a implementace objektu
interface – rozhraní objektu, tedy to jakým voláním rozumí
implementation – to jakým způsobem objekt na volání reaguje
INTERFACE = interface
CLASS = interface + implementation
když to otočíme tak interface je obsaženo jak v CLASS tak v INTERFACE takže:
interface = INTERFACE || CLASS
David Grudl #10
Aha, rozumím. Já měl na mysli spíš sjednocení, než průnik.
MartinMystikJonas #11
#10 David Grudl, Takže jaký je kontext použití té proměnné? Nenapadá mě žádné použití, kde bych tu proměnnou požíval ve smyslu sjednocení.
David Grudl #12
#11 MartinMystikJonas, už jsem to tu zmiňoval, třeba
$class_name
https://www.php.net/…class-of.phpMiloslav Ponkrác #13
Pokud to nechcete nazývat třídou, tak se co svět světem stojí se už léta ustálil název „objektový typ“.
„Interface“ není čistě rozhraní objektu, je to také typová informace o typové kompatibilitě. Dokonce v zásadě teoreticky nic podstatného nebrání tomu, aby v příští verzi PHP dovoloval „interface“ také implementaci metod.
Objektové typy, tedy class, interface a trait řeší různé kombinace čtveřice: 1) rozhraní (API) třídy, 2) typ a typovou kompatibilitu, 3) možnost (jednoduché či vícenásobné) dědičnosti, 4) implementací.
MartinMystikJonas #14
#12 David Grudl, Ale v tomhle případě to je přesně to o čem píšu. Použití metody is_subclass_of je v tom, že mi umožní zkontrolovat, zda daný objekt bude rozumět určitému volání. Kontroluji teda zda jeho rozhraní odpovídá interface dané CLASS nebo interface daného INTERFACE.
To co si myslím, že hledáme je název pro rozhraní třídy ve smyslu „rozhraní objektu, tedy to jakým voláním rozumí“. Je pravda, že použití názvu interface vede ke zmatení, protože interface (rozhraní) je jak rozhraní objektu v abstraktním smyslu tak klíčové slovo INTERFACE popisující konkrétní konstrukci jazyka.
Co jsme se ale snažil především říct je, že vidím chybu v tvrzení, že interface je podtyp třídy. Je tomu spíše naopak tedy třída je podtyp rozhraní. Přesněji řešeno CLASS i INTERFACE je interface v abstraktním smyslu. Ale nikoliv INTERFACE je CLASS.
David Grudl #15
#14 MartinMystikJonas, Rozhraní je v podstatě totéž, jako kompletně abstraktní třída. Tedy je speciálním případem třídy. Tedy je podmnožinou tříd.
Taco #16
Když stojím v nějaké funkci, a chci, aby mi argumentem přišel nějaký konkrétní objekt, tak mě nezajímá, jestli ten objekt je class, nebo interface, nebo abstract class, nebo trait. A dokonce mě ani nezajímá, jakou má implementaci. Vlastně jediné, co potřebuju je, aby ten objekt měl tuto a tuto metodu a já ji mohl úspěšně zavolat.
Pak ještě mohu řešit, že má přijít hodnota nějakého nominálního typu (to jsou takové ty interface bez metod).
No, a na hraně toho je ten typový filtr v argumentu. Tam dám něco, co splňuje moje požadavky.
Osobně tomu prostě říkám typ. V mém vidění světa je String nebo Integer typ uchopitelný stejným způsobem jako třeba Countable či ArrayAccess.
Tento článek byl uzavřen. Už není možné k němu přidávat komentáře.