« Over op PHP 5.4 | Crontabs: url aanroepen » |
Nieuw in PHP 5.4 pt 2: Traits
2. Traits
Dit is het voor al veel eerder geplande deel 2 uit mijn serie: wat is nieuw in PHP 5.4
Het eerste wat natuurlijk wijzigt, is dat "trait" nu een gereserveerd woord is. Mocht je dus functies of classes danwel constantes aangemaakt hebben met deze naam, dan dient dat aangepast te worden.
Wat is een trait nu eigenlijk?
Het is min of meer een container met functies die aan te roepen zijn vanuit een class, zonder dat ze deel uit maken van de class zelf óf de parent class. Voordeel is dat functies die in verschillende classes keer op keer terug komen, zonder dat die verschillende classes een relatie hebben toch maar 1x gedefinieerd hoeven te worden, of zonder dat er een parent class gemaakt moet worden de al dit soort functies bevat.
In tegenstelling tot verschillende andere programmeertalen, kan in php een class maar 1 parent hebben. Traits bieden hier een oplossing.
Voorbeeld:
<?php trait HelloWorld { public function sayHello() { echo 'Hello World'; } public function uitroepteken() { echo '!!'; } } class MyTest1 { use HelloWorld; public function uitroepteken() { echo '!'; } } $o = new MyTest1(); $o->sayHello(); $o->uitroepteken(); ?>
Bovenstaande code zal in eerste instantie gaan zoeken in de class MyTest1 naar een method genaamd sayHello(). Aangezien deze niet gevonden wordt, wordt verder gezocht naar deze method in de trait HelloWorld. Daar wordt deze gevonden en uitgevoerd.
Echter, de method uitroepteken() wordt wel gevonden in de class zelf. Deze heeft dan voorrang boven de method in de trait. Bijgevolg wordt er dus ook maar 1 uitroepteken getoond.
En trait heeft, eigenlijk in eerste instantie tot mijn verbazing, voorrang boven een parent-class:
trait HelloWorld { public function sayHello() { echo 'Hello World'; } public function uitroepteken() { echo '!!'; } } class MyParent { public function sayHello() { echo 'Hallo Wereld'; } } class MyTest1 extends MyParent { use HelloWorld; public function uitroepteken() { echo '!'; } } $o = new MyTest1(); $o->sayHello(); $o->uitroepteken();
Dit geeft precies dezelfde output als het eerste script: "Hello World!". In het Engels dus, zoals in de trait gedefinieerd.
Een trait gedraagt zich dus als een onderdeel van de class waarin deze met USE "geinclude" wordt. In bovenstaand voorbeeld zouden we natuurlijk ook het use-commando kunnen opnemen in de class MyParent.
Traits zijn dus een manier om methods te "includen" in een of meerdere classes. Vergelijk het om een simpel voorbeeld te nemen met een header.php die op elke pagina van een site geinclude wordt, zodat een wijziging in die header ook steeds effect heeft op alle pagina's.
Met classes hadden we de mogelijkheid gehad om zulke functionaliteit te bereiken door een parent class aan te maken met al deze functies, maar dat zou beperkingen hebben: je kunt dan niet delen van die functies opsplitsen.
Voorbeeld: veel classes in je project hebben methods nodig om invoer te valideren. Een aantal heeft methods nodig om mails te versturen.
Zou je nu de parent classe voorzien van al deze functionaliteit, dan heb je voor de classes die niets met mail doen te veel. Dát zou nog met een constructie parent-validatie > parent-mail ->myclass kunnen worden opgelost, maar dan gaat hetzelfde verhaal op voor de class die alleen maar mail moet voorbereiden.
met traits wordt dat in de betreffende myclass dan
<?php use validate; use mail; ?>
Of:
<?php use validate, mail; ?>
Conflicten?
Wat nu als er in de ene trait een functie voorkomt, die ook in een andere trait staat en je wilt beide traits gebruiken. Ook daar is aan gedacht: Met het nieuwe keyword InsteadOf kan een keuze gemaakt worden uit een van de dubbel voorkomende methods. Als je beide wilt gebruiken, dan zul je dus iets aan de naamgeving moeten doen. Het keyword "as" biedt daar uitkomst:
<?php use validate, mail { mail::dubbel insteadof validate; validate::mijnfunctie as func; }; ?>
Bovenstaande code zorgt ervoor, dat de method dubbel(), die kennelijk zowel in de trait mail als in validate voorkomt, alleen in de trait mail wordt bekeken. In de trait validate komt kennelijk een method genaamd MijnFunctie voor. Ofwel om een conflict met een dubbel naamgeving op te lossen, ofwel omdat ik gewoon niet van veel typen hou, wordt met "as" en andere naam toegekend aan deze method.