Nedávno bylo anoncováno spuštění oficiální wiki pod PHP doménou - http://wiki.php.net. Má přehledně zastřešovat informace, které byly dříve například na jiné poloficiální php wiki, je tam tedy nastíněna roadmapa PHP, různá RFC, TODO atd. A právě na jeden návrh bych se rád podával podrobněji. Je to návrh traits - (slovník říká rysy - nicméně dál ponechám bez překladu). Je to velice zajímavý návrch, který nám umožní zvýšit znovupoužitelnost kódu v prostředích s jednoduchou dědičností jako je PHP. V tomto a následujícím článku se pokusím v krátkosti naznačit k čemu by se traity mohly hodit.
PHP je jak známo jazyk s jednoduchou dědičností a více interfaces po vzoru např. Javy, na rozdíl od C++, které podporuje vícenásobnou dědičnost, nebo Ruby a jeho mixiny. Prostředí s jednoduchou dědičností mohou v určitých ohledech vývojáře limitovat a stavět ho před problém menší znuvupoužitelnosti při zachování čisté hierarchie tříd. A právě zde mohou pomoci traits.
Trait je malá jednotka kódu, která je zamýšlena pro specifickou funkčnost, která rozšíří jednoduchou dědičnost horizontální kompozicí. Není ji možné samostatně instancovat. Uff takhle nějak je to v tom RFC, ale po pravdě tomu moc nerozumím. Lepší bude příklad.
Následující příklad ukazuje, jak rozšiřovat reflection API tak, aby se mohlo přes reflection přistupovat ke komentářům
class ezcReflectionMethod extends ReflectionMethod { /* ... */ function getReturnType() { /*1*/ } function getReturnDescription() { /*2*/ } /* ... */ } class ezcReflectionFunction extends ReflectionFunction { /* ... */ function getReturnType() { /*1*/ } function getReturnDescription() { /*2*/ } /* ... */ }
Jak ReflectionMethod tak ReflectionFunction musí být rozšířeny stejným kódem, což určitě není to pravé. V některých případech je možné použít nějakou společnou základní třídu, dost často to ale možné není, protože základní třídu nemáme nějakým způsobem pod kontrolou - je třeba součástí nějakého frameworku, nebo je napsaná jako php rozšíření v C/C++. Právě traity nám nabízí funkcionalitu, jak na to.
trait ezcReflectionReturnInfo { function getReturnType() { /*1*/ } function getReturnDescription() { /*2*/ } } class ezcReflectionMethod extends ReflectionMethod { use ezcReflectionReturnInfo; /* ... */ } class ezcReflectionFunction extends ReflectionFunction { use ezcReflectionReturnInfo; /* ... */ }
Tím jsem dosáhli přesně stejného efektu jako předtím, ovšem rozšiřující kód se nám nikde neduplikuje. Příště se zmíním trochu podrobněji o navrhované syntaxy traitů a jejich vlastnostech.
Komentáře (1)
Viz také Extension method v Nette.
Komentáře jsou uzavřeny.