Skip to content

Instantly share code, notes, and snippets.

@smichaelsen
Last active March 11, 2016 16:17
Show Gist options
  • Save smichaelsen/b5b742ad66e89cbb8daf to your computer and use it in GitHub Desktop.
Save smichaelsen/b5b742ad66e89cbb8daf to your computer and use it in GitHub Desktop.
Idea: Injection Traits #typo3 #extbase
<?php
class A
{
/**
* In TYPO3 (Extbase) you can use a simple @inject annotation to get an instance of the class specified with
* the @var annotation ready-to-use when your class is instanciated.
* However you're discouraged to use that variant for performance reasons.
*
* @var \FirstFactory
* @inject
*/
protected $firstFactory;
// ----------------------------------------------------------------- //
/**
* @var \SecondFactory
*/
protected $secondFactory;
/**
* Nowadays this is the common way for dependency injection in TYPO3 even though it is a little bit longer.
* When your class is instanciated all public inject* methods will be called automagically and supplied with
* the desired objects.
*
* Disadvantage of both methods: Injections will always happen when you use this class. You might end up using a
* lot of service classes in your methods but you're not using every service in every method so you get classes
* injected which you're not using. That's bad for performance of course (consider these service classes may have
* injections as well). Also some heavy reflection crunching (and caching) is done to analyse which classes are needed.
*
* @param \SecondFactory $secondFactory
*/
public function injectSecondFactory(\SecondFactory $secondFactory)
{
$this->secondFactory = $secondFactory;
}
// ----------------------------------------------------------------- //
public function myMethod()
{
/**
* Instead of using dependency injection you could instanciate your services manually to make sure you only
* load what you need. From a performance point of view: Good choice!
*
* Disadvantage: Not only is it hazzly to write, it also is bad for the testability of your code.
* When using dependency injection you can pass mock objects as services to your class, but with this variant
* it's not really possible. To stay testable your service classes need to be properties of your class.
*/
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class);
$thirdFactory = $objectManager->get(\ThirdFactory::class);
}
// ----------------------------------------------------------------- //
use FourthFactoryInjection;
public function myOtherMethod()
{
/**
* @see FourthFactoryInjection.php
*/
$this->getFourthFactory();
}
}
<?php
/**
* Here's my idea:
* Using traits i'd like to avoid the disadvantages of all known injection variants.
* The trait provides a property $_fourthFactory to the class using it, so you can always
* inject a mock object in your tests. When you want to call your service always use the getter
* method and it will be instanciated on demand.
*
* What do you think? I'd be happy to hear your feedback.
*/
trait FourthFactoryInjection
{
/**
* @var \FourthFactory
*/
private $_fourthFactory;
/**
* @return \FourthFactory
*/
protected function getFourthFactory()
{
if (!$this->_fourthFactory instanceof \FourthFactory) {
$this->_fourthFactory = GeneralUtility::makeInstance(ObjectManager::class)->get(\FourthFactory::class);
}
return $this->_fourthFactory;
}
}
@afoeder
Copy link

afoeder commented Mar 11, 2016

Well, @NamelessCoder said it already: I am all and exclusively for constructor injection for the reasons the Symfony doc already state: http://symfony.com/doc/current/components/dependency_injection/types.html

Only constructor injection guarantees intrinsically that the dependency is there, everything other is just "hoping".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment