Autor Zpráva
ForestCZE
Profil
Zdravím, nevím si rady s dědičností v PHP. Mám abstraktní třídu:

abstract class AdminManager
{
  public function nejakaMetoda(): void
  {
    $this->database...
  }
}

Zde potřebuji předat závislost, abych se dostal k databázi.

A poté mám třídu:

final class UserManager extends AdminManager implements IAuthenticator
{
  private $database;
  private $passwords;
    
  public function __construct(Database $database, Passwords $passwords)
  {
    $this->database = $database;
    $this->passwords = $passwords;
  }
}

Tuším, že musím nějak zavolat předka:

parent:__construct();

Jak a v které třídě zavolat toho předka?
Radek9
Profil
ForestCZE:
parent:__construct();
Skoro. Dvě dvojtečky: parent::__construct();
ForestCZE
Profil
Radek9:
S tou dvojtečkou jsem jenom seknul. O tu vůbec nejde.

Jde o to, že mám:

abstract class AdminManager
{  
    private $database;
    
    public function __construct(Database $database)
    {
        $this->database = $database;
    }
}

final class UserManager extends AdminManager implements IAuthenticator
{
    private $passwords;
    
    public function __construct(Passwords $passwords)
    {
        $this->passwords = $passwords;
        parent::__construct($database);
    }
}

Automaticky mi ten konstruktor předka vyhodí, že chce argument databáze a já netuším, kde ho vzít.
ForestCZE
Profil
Tak vyřešeno. Musí to být takto:

private $database;
    private $passwords;
    
    public function __construct(Database $database, Passwords $passwords)
    {
        $this->database = $database;
        $this->passwords = $passwords;
        parent::__construct($database);
    }
Keeehi
Profil
ForestCZE:
Úplně nevím o co se snažíš ale jsi si jistý že private je správně zvolená viditelnost? Já si téměř vždy vystačím s public a protected. Private atributy právě dělají problémy při dědičnosti. Mají smysl pokud bys potřeboval něco v rodiči skrýt před potomkem. Ale to v tvém případě není to co děláš. Ten objekt bude mít v důsledku zbytečně 2x odkaz na databázi. Jednou pro metody předka a jednou pro metody potomka.
ForestCZE
Profil
Keeehi:
Celou dobu se nemohu zbavit toho pocitu, že tam bude 2x odkaz na objekt, takže skvělý postřeh. Jde o to, že mám hlavní třídu UserManager, kde je několik metod. A poté bych chtěl druhou třídu AdminManager, která má sloužit ČISTĚ k rozšíření třídy kvůli přehlednosti, abych neměl všechny metody v jedné třídě. Takže bych rád, aby tyto dvě třídy měly společnou instanci. Jak by to tedy mohlo být lépe? Děkuji.
Kcko
Profil
Keeehi:
Používá Nette a Nette používá autowiring, takže je v důsledku jedno protože vždy existuje 1 instance DB.
Keeehi
Profil
Kcko:
To co jsem tím měl na mysli je, že interně ten objekt bude mít dvě proměnné database. Jednou AdminManager::$database a jednou UserManager::$database. Ano, v obou bude stejná instance třídy pro komunikaaci s databází (ani ne tak kvůli autowiringu ale kvůli tomu volaní rodiče v konstruktoru). O to tady ale vůbec nejde. Fungovalo by to s tím? Jasně. Přidávalo vy to nějakou významnou zátěž? Jeden odkaz na objekt navíc určitě nic dramatického neznamená. O co tady jde je čistota návrhu.

ForestCZE:
Jak by to tedy mohlo být lépe?
Těžko říct. Ono to záleží co má co dělat. Taky na práci s databází používám jinou knihovnu než nette/database, takže pokud tam jsou používané nějaké konvence tak je neznám. Ale obecně. Abstract se používá u třídy u které nechceš aby se z ní dala vytvořit instance. Tedy nějakého obecného předka, který implementuje nějakou funkčnost, ale nedává smysl z něj vytvářet instance. Měl by mít pak ale taky obecné pojmenování. Ve tvém případě mi to ale přijde moc konkrétní. Tudíž buď z AdminManagera chceč tvořit instnace a pak tam máš abstract navíc, nebo to má být obecný předek všech dalších xxxManagerů ale pak by se měl jmenovat něco jako BaseManager, DatabaseManager, Manager, nebo tak něco. Já vím, pojmenovávání je jedna z nějtěžších úloh programátora :D
Final zase naopak zabrání, aby někdo danou třídu rozšiřoval. Ovšem je tak trochu zbytečné. Není moc důvodů proč by sis to musel explicitně zakazovat. Pokud nepotřebuješ vytvářet ve svém projektu dalšího potomka té třídy, tak ho prostě nevytvoříš. Naopak, když zjistíš, že bys to kvůli něčemu potřeboval, nebudeš se muset vracet a klíčové slova final mazat.
Jak už jsem psal, private atributy většinou moc nepotřebuješ a to samé platí i o metodách. Protected schová před vnějším světem vše pro interní potřeby objektu stejně dobře jako private, ale dovolí provádět změny při dědičnosti.
Další dobrou věcí je nepoužívat public atributy, jelikož umožňují zásah do objektu zvenčí. Jasně, ve svém projektu si u instance nějaké vlastní třídy nepřepíšeš omylem nějaký atribut nějakou blbostí ale je to dobrý zvyk. K tomu máme settry a gettry, případně construct. Pokud se používají metody, mohou vynutit třeba datový typ nebo v nich může být kód který ověří, že se tam nesnaží někdo vložit nějaký nesmysl.

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:

0