Attention

TYPO3 v10 has reached end-of-life as of April 30th 2023 and is no longer being maintained. Use the version switcher on the top left of this page to select documentation for a supported version of TYPO3.

Need more time before upgrading? You can purchase Extended Long Term Support (ELTS) for TYPO3 v10 here: TYPO3 ELTS.

Traits

Characteristica

  • A trait MAY access properties or methods of the class it is embedded in.

  • A trait MUST be combined with an interface. Classes using a trait must implement at least this interface.

  • A trait interface MUST have a default implementation trait.

Rationale

There is one specific feature that traits provide other abstraction solutions like services or static extraction do not: A trait is embedded within the class that consumes it and as such can directly access methods and properties of this class. A trait typically holds state in a property of the class. If this feature is not needed, traits should not be used. Thus, the trait itself may even have a dependency to the class it is embedded in, even if this is rather discouraged.

A simple way to look at this is to see the interface as the main feature with the trait providing a single or maybe two default implementations of the interface for a specific class.

One usage of traits is the removal of boilerplate code. While object creation and dependency injection is still a not resolved issue in the core, this area is probably a good example where a couple of traits would be really useful to autowire default functionality like logging into classes with very little developer effort and in a simple and understandable way. It should however be kept in mind that traits must always be used with care and should stay as a relatively seldom used solution. This is one reason why the current getLanguageService() and similar boilerplate methods are kept within classes directly for now and is not extracted to traits: Both container system and global scope objects are currently not finally decided and we don’t want to have relatively hard to deprecate and remove traits at this point.

Good Examples

  • \Symfony\Component\DependencyInjection\ContainerAwareInterface with \Symfony\Component\DependencyInjection\ContainerAwareTrait as default implementation

    • The ContainerAwareInterface is tested to within the dependency injection system of symfony and the trait is a simple default implementation that easily adds the interface functionality to a given class.

    • Good naming.

    • Clear scope.

  • LoggerAwareInterface with a default trait.

Bad Examples

  • Old \TYPO3\CMS\FluidStyledContent\ViewHelpers\Menu\MenuViewHelperTrait (available in previous TYPO3 versions)

    • Contains only protected methods, can not be combined with interface.

    • Contains getTypoScriptFrontendController(), hides this dependency in the consuming class.

    • No interface.

    • It would have probably been better to add the trait code to a full class and just use it in the according view helpers (composition) or implement it as abstract.

For these reasons the trait has been dissolved into an AbstractMenuViewHelper.