Autor Zpráva
interface
Profil *
Zdravím

Chtěl bych poprosit, jestli by mi někdo zkušený nenapsal praktické využití interface v php.
Našel jsem dost článků podobných Tomuto, ale stále tomu nerozumím.
K čemu je dobré si zapsat prázdné třídy a pak je napsat vlastně celé znovu? Jediný smysl vidím v tom, abych na něco nezapomněl - ale to asi nebude ono.
Navíc jsem četl že jsou interface "náhrada" za dědění více tříd - ale to se opět dostávám k tomu, že dědím (implementuji) jen kostru (seznam metod) .
Kcko
Profil
Trida ktera implementuje Interface musi metody Interfacu "naplnit". Proste tim si zajistis ze je tam napises
TomášK
Profil
Pokud nějaká třída implementuje interface, pak se můžeš spolehnout na to, že má určitou sadu metod, určitý způsob, jak k objektu můžeš přistoupit. Můžeš pak třeba říct, že jako parametr funkce chceš takový objekt, který implementuje toto interface.

Příklad - řazení pole objektů
Máme pole objektů, které chceme seřadit. Potřebujeme je tedy porovnávat mezi sebou - třeba metoda compareTo(). Abychom měli zaručené, že všechny v poli objekty mají tuto metodu, pak musíme říct, že v poli můžou být objekty buď
a, musí být potomky třídy, která tuto metodu má (v tomhle případě nevhodné)
b, musí implementovat interface Comparable, který má jedinou metodu compareTo()

Některé jazyky mají interface, některé vícenásobnou dědičnost, pomocí které jde podobné chování nasimulovat také.
Alphard
Profil
interface:
abych na něco nezapomněl - ale to asi nebude ono.
Nebo aby nezapomněl někdo jiný.

Zkusím uvést jiný příklad:
Framework Nette se snaží co nejvíce usnadnit práci, ale zároveň nenutit programátorům vše do posledních detailů. Je to vidět třeba u Přihlašování uživatelů.
Je třeba předem vědět, jak bude vypadat třída pro ověřování přihlašovacích údajů, protože na tom závisí další funkce frameworku. Problém je v tom, že tu třídu si vytvoří až sami uživatelé. Proto je daná třída v Nette zapsaná jako interface. Vývojáři frameworku mohou s klidem rozšiřovat funkce, protože se mohou spolehnout na to, že určité metody, které potřebují, tam skutečně budou a programátoři mají také usnadněnou práci, protože se jenom podívají na interface, napíší metody, které jsou potřeba a všechno funguje.

Pak to vypadá takhle:
Rozhraní dané frameworkem:
interface IAuthenticator
{
	/**#@+ Credential key */
	const USERNAME = 'username';
	const PASSWORD = 'password';
	/**#@-*/

	/**#@+ Exception error code */
	const IDENTITY_NOT_FOUND = 1;
	const INVALID_CREDENTIAL = 2;
	const FAILURE = 3;
	/**#@-*/

	/**
	 * Performs an authentication against e.g. database.
	 * and returns IIdentity on success or throws AuthenticationException
	 *
	 * @param  array
	 * @return IIdentity
	 * @throws AuthenticationException
	 */
	function authenticate(array $credentials);

}


Konkrétní implementace programátora:
class MyAuthenticator extends Object implements IAuthenticator
{

    public function authenticate(array $credentials)
    {
        $username = $credentials[self::USERNAME];
        $password = sha1($credentials[self::PASSWORD] . $credentials[self::USERNAME]);

        // přečteme záznam o uživateli z databáze
        $row = dibi::fetch('SELECT realname, password FROM users WHERE login=%s', $username);

        if (!$row) { // uživatel nenalezen?
            throw new AuthenticationException("User '$username' not found.", self::IDENTITY_NOT_FOUND);
        }

        if ($row->password !== $password) { // hesla se neshodují?
            throw new AuthenticationException("Invalid password.", self::INVALID_CREDENTIAL);
        }

        return new Identity($row->realname); // vrátíme identitu
    }

} 


Jak vidíte, není zde prostor pro chyby a nejsme k ničemu nuceni. Klidně bychom mohli informace o uživatelích ukládat v souborech, stačilo by přepsat třídu MyAuthenticator.
interface
Profil *
Aha. Díky tak už je mi to jasné.

Alphard
počítám, že někde v dokumentaci pak musí být napsáno, že pro přihlašování mám použít konkrétní interface.


Ještě se zeptám na jednu věc. Jak se tedy v php řeší vícenásobná dědičnost? každá třída může mít pokud vím jen jednoho rodiče.
Když bych měl tři třídy AAA, BBB, CCC jaké je nejlepší řešení když bych chtěl, aby třída CCC zdědila AAA i BBB (a třídy AAA a BBB bych nechtěl dat do jedné protože spolu nesouvisí)?
Timy
Profil
interface
Ještě se zeptám na jednu věc. Jak se tedy v php řeší vícenásobná dědičnost? každá třída může mít pokud vím jen jednoho rodiče.
Dej konkrétní příklad, kdy bys to chtěl použít – obvykle nejlepší způsob jak dosáhnout vícenásobné dědičnosti je obloukem se jí vyhnout a udělat to jinak :-).
interface
Profil *
Timy

Malá ukázka co mě napadla:
class jidlo
{
	function druh ()
	{
		druh jidla co ji dane zvire
	}
	function mnozstvi ()
	{
		mnozstvi jidla co ji dane zvire
	}
}

class klec
{
	function velikost ()
	{
		potrebna velikost klece pro dane zvire
	}
	function prostredi ()
	{
		potrebne prostredi pro zivot daneho zvirete
	}
}

class zvire extends jidlo+klec
{
	pro kazde zvire by se hodila jak trida jidlo tak i trida klec. tridy jidlo a klec by samozrejme slouzily 
	i k jinym vecem - trida jidlo by pak treba obsahovala metodu pro vypis celkoveho sezraneho jidla za urcite 
	obdobi a trida klec by mela treba metodu na vypis celkoveho zabraneho prostoru vsemi zviraty
}



Timy
Profil
interface
Tady je to jednoduché – třída „zvire“ určitě nemá dědit ani z třídy „jidlo“, ani z „klec“ :-). Obojí je nesmysl, zvíře není speciálním případem klece. Zde by to mohlo být třeba tak, že třída klec si bude uchovávat referenci na zvire, které je v ní umístěné. Ale nebude dědit, bude to jen součást vnitřního stavu objektu.
interface
Profil *
Timy
uznávám že to byl dost špatný příklad.
když to vezmu jinak mohly by to byt třídy zvíře a masožravci a pak by je dědila třída lev.
nebo třeba vlastnosti matky, vlastnosti otce a dědilo by je dítě.

šlo mi spíš to, jak by se to řešilo když by k něčemu takovému došlo.
Mastodont
Profil
mohly by to byt třídy zvíře a masožravci
Masožravec je speciální typ zvířete, takže nemohly. Dědičnost je v tomto případě zvíře -> masožravec ->lev
interface
Profil *
ok ok ok prostě to budu brát tak jak napsal Timy a vícenásobné dědičnosti vyhnu. protože jak se tak dívám tak můj poslední příklad s vlastnostmi otce a matky taky můžu jednoduše změnit na vlastnosti rodičů.

Díky moc za všechny odpovědi
TomášK
Profil
interface
Jak píše timy - řešilo by se to změnou návrhu. Myslím, že interface byl zaveden jako nahrazení vícenásobné dědičnosti, dědění od více tříd (z nichž žádná nemá sloužit jako rozhraní) zřejmě bylo nežádoucí a interface tomu zabrání. Pokud bys chtěl využít takového dědění, musíš zvolit jazyk, kde to jde, a i pak bys měl objektovému modelu rozumět hodně dobře na to, abys opravdu věděl, co děláš a co to přináší za rizika - např. diamant . Sám neznám žádný příklad, kdy by to bylo užitečné.
Lamicz
Profil
Interface do jiste miry nahrazuje vicenasobne dedeni, i kdyz trochu jinym zpusobem. Zkuste si tento test:
<?php

interface ITest {
}

class Test implements ITest {
}

$o = new Test;
if($o instanceof ITest){
	echo "OK";
}

?>
G3n3sis19
Profil
Alphard:
ývojáři frameworku mohou s klidem rozšiřovat funkce, protože se mohou spolehnout na to, že určité metody, které potřebují, tam skutečně budou a programátoři mají také usnadněnou práci, protože se jenom podívají na interface, napíší metody, které jsou potřeba a všechno funguje.
Takže jestli to chápu, interface je vlastně takový pomocník, který říká, jaké metody jsou potřeba k nově vytvořené třídě. Ale stejně nevidím praktické využití, jak by se tím mohla třída vylepšit
Alphard
Profil
Ano. Praktické využití nepochybně má, v příkladech se nebudu opakovat, ale máte pravdu, že vše, co jde udělat s interface, uděláte i bez něj.

Zvlášť při práci v týmu např. [#13]. Definuji nějaký interface, který musí kolega implementovat, já s tím počítám v dalším kódu. Dám tam ale podmínku, aby se to ověřilo. Když kolega náhodou zapomene implementovat nějakou metodu, jasně mu to vypíše, co nesplnil, kdyby tam interface nebyl, mohla by chyba probublat o několik tříd dál, kde by pak chyběla nějaká metoda, aplikace by skončila fatal errorem. Nejhorší následky by byly při podmíněném volání dané metody, při rychlém testování by se to třeba ani nezjistilo.
Bertram
Profil
Ahoj,
za zmínku ještě stojí že, rozhraní je taková domluva o tom jakou funkcionalitu budou dané objekty poskytovat. A to i objekty, které spolu vůbec nesouvisí, což se dá použít jako Type Hinting, takže máme jistotu, že předáváme objekt, který implementuje námi požadované metody.
netprd
Profil
Krásný příklad využití Interface je použití předdefinovaného rozhraní IteratorAggregate díky němuž můžete objekt procházet jako pole(Array)

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: