Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell...

75
Timon Schroeter 1 www.php-schulung.de Dependency Injection DI

Transcript of Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell...

Page 1: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 1 www.php-schulung.de

Dependency Injection

DI

Page 2: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 2 www.php-schulung.de

● Developer & Consultant: PHP, Symfony 2 etc.– www.php-entwickler-berlin.de

● Trainer & Coach: Symfony 2 workshops 1-5 days– www.php-schulung.de

● Available for Your project – [email protected]

Page 3: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 3 www.php-schulung.de

What is Dependency Injection?

● Your answer?

Page 4: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 4 www.php-schulung.de

Dependency Injection in a Nutshell

● software design pattern● push (instead of pull) dependencies● loose coupling● easy testing● high code quality● supported by many frameworks● very well supported by Symfony 2

Page 5: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 5 www.php-schulung.de

Structure of this presentation

● Why do we want Dependency Injection?● Code example: DI for generic PHP classes● Code example: DI in Symfony 2

Page 6: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 6 www.php-schulung.de

Structure of this presentation

● Why do we want Dependency Injection?● Code example: DI for generic PHP classes● Code example: DI in Symfony 2

You are here

Page 7: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 7 www.php-schulung.de

Why do we want to use Dependency Injection?

● Who has ever worked on a project that was more than 2 years old?

Page 8: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 8 www.php-schulung.de

Project without a really good QA and testing strategy

Project Lifetime

Time to Feature / Bugfix

Page 9: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 9 www.php-schulung.de

Project without a really good QA and testing strategy

Project Lifetime

Time to Feature / Bugfix

Business Value of Feature / Bugfix

Page 10: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 10 www.php-schulung.de

Project without a really good QA and testing strategy

Project Lifetime

Time to Feature / Bugfix

Business Value of Feature / Bugfix

Death

Pain

Page 11: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 11 www.php-schulung.de

Project with a really good QA and testing strategy

Project Lifetime

Time to Feature / Bugfix

Business Value of Feature / Bugfix

Page 12: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 12 www.php-schulung.de

Project with a really good QA and testing strategy

Project Lifetime

Time to Feature / Bugfix

Business Value of Feature / Bugfix

In old industries,the big eat the small.

In the tech startup world,the fast eat the slow.

Page 13: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 13 www.php-schulung.de

Good QA and Testing Strategy includes a mix of:

● Acceptance Tests– Manual testing by real users

● Functional Tests– Automated backbox test (Selenium etc.)

● Integration Tests– Tests two or more classes together

● (real) Unit Tests– Tests one(!) class

Page 14: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 14 www.php-schulung.de

Good QA and Testing Strategy includes a mix of:

● Acceptance Tests– Manual testing by real users

● Functional Tests– Automated backbox test (Selenium etc.)

● Integration Tests– Tests two or more classes together

● (real) Unit Tests– Tests one(!) class

Testing can be hard.

Reality check:

How do You test?

Page 15: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 15 www.php-schulung.de

Not all tests are created equal

Specificity

Stability

UnitTests

AcceptanceTests

FunctionalTests

IntegrationTests

Page 16: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 16 www.php-schulung.de

Specificity

Stability

UnitTests

AcceptanceTests

FunctionalTests

IntegrationTestsAlwasy feasible,

even with low qualitylegacy code

Alwasy feasible,even with low quality

legacy code

Most valuable,require high qualitywell structured code

Not all tests are created equal

Page 17: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 17 www.php-schulung.de

(Real) Unit Tests

● Test a single unit of code, i.e. a single class● Validate correct functionality and API of each class● Help avoid regressions● Facilitate migrations (server, PHP version etc.)● Ensure backwards compatability of new code

Page 18: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 18 www.php-schulung.de

(Real) Unit Tests

● Test a single unit of code, i.e. a single class● Validate correct functionality and API of each class● Help avoid regressions● Facilitate migrations (server, PHP version etc.)● Ensure backwards compatability of new code

stable well designed API

small dedicatedclasses & methods

stable well designed API

Page 19: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 19 www.php-schulung.de

Real Unit Tests

● Test a single unit of code, i.e. a single class● Validate correct functionality and API of each class● Help avoid regressions● Facilitate migrations (server, PHP version etc.)● Ensure backwards compatability of new code

stable well designed API

small dedicatedclasses & methods

We need to be able toreplace (mock/stub)

dependencies dynamically

stable well designed API

Page 20: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 20 www.php-schulung.de

Structure of this presentation

● Why do we want Dependency Injection?● Code example: DI for generic PHP classes● Code example: DI in Symfony 2

You are here

Page 21: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 21 www.php-schulung.de

<?phpuse Guzzle\Http\Client;use Acme\Logger\XmlLogger;

private $client;private $logger;

class FeedAggregator {__construct () {

$this->client = new Client();$this->logger = new XmlLogger();

}

public function retrieveFeed ($baseurl, $path) {$request = $this->client->setBaseUrl($baseurl)->get($path);$response = $request->send();if (200 != $response->getStatusCode()) {

$this->logger->log('Could not get: '.$host.$path);return null;

}

return $response->getBody();}// ...

}

Why is this classdifficult to unit test?

Page 22: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 22 www.php-schulung.de

<?phpuse Guzzle\Http\Client;use Acme\Logger\XmlLogger;

private $client;private $logger;

class FeedAggregator {__construct () {

$this->client = new Client();$this->logger = new XmlLogger();

}

public function retrieveFeed ($baseurl, $path) {$request = $this->client->setBaseUrl($baseurl)->get($path);$response = $request->send();if (200 != $response->getStatusCode()) {

$this->logger->log('Could not get: '.$host.$path);return null;

}

return $response->getBody();}// ...

}

What if we want unit tests to run fastwithout waiting for the network?

Why is this classdifficult to unit test?

Page 23: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 23 www.php-schulung.de

<?phpuse Guzzle\Http\Client;use Acme\Logger\XmlLogger;

private $client;private $logger;

class FeedAggregator {__construct () {

$this->client = new Client();$this->logger = new XmlLogger();

}

public function retrieveFeed ($baseurl, $path) {$request = $this->client->setBaseUrl($baseurl)->get($path);$response = $request->send();if (200 != $response->getStatusCode()) {

$this->logger->log('Could not get: '.$host.$path);return null;

}

return $response->getBody();}// ...

}

What if we want unit tests to run fastwithout waiting for the network?

What if we want unit tests to run fastwithout logging?

What if we want unit tests to run fastwithout logging?

Why is this classdifficult to unit test?

Page 24: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 24 www.php-schulung.de

<?phpuse Guzzle\Http\Client;use Acme\Logger\XmlLogger;

private $client;private $logger;

class FeedAggregator {__construct () {

$this->client = new Client();$this->logger = new XmlLogger();

}

public function retrieveFeed ($baseurl, $path) {$request = $this->client->setBaseUrl($baseurl)->get($path);$response = $request->send();if (200 != $response->getStatusCode()) {

$this->logger->log('Could not get: '.$host.$path);return null;

}

return $response->getBody();}// ...

}

What if we want unit tests to run fastwithout waiting for the network?

What if we ever want to

use a different HTTP client?

What if we want unit tests to run fastwithout logging?

What if we want unit tests to run fastwithout logging?

Why is this classdifficult to unit test?

Page 25: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 25 www.php-schulung.de

<?phpuse Guzzle\Http\Client;use Acme\Logger\XmlLogger;

private $client;private $logger;

class FeedAggregator {__construct () {

$this->client = new Client();$this->logger = new XmlLogger();

}

public function retrieveFeed ($baseurl, $path) {$request = $this->client->setBaseUrl($baseurl)->get($path);$response = $request->send();if (200 != $response->getStatusCode()) {

$this->logger->log('Could not get: '.$host.$path);return null;

}

return $response->getBody();}// ...

}

What if we want unit tests to run fastwithout waiting for the network?

What if we ever want to

use a different HTTP client?

What if we want unit tests to run fastwithout logging?

What if we ever want to

use a different logger class?

What if we want unit tests to run fastwithout logging?

Why is this classdifficult to unit test?

Page 26: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 26 www.php-schulung.de

<?phpuse Guzzle\Http\Client;use Acme\Logger\XmlLogger;

private $client;private $logger;

class FeedAggregator {__construct () {

$this->client = new Client();$this->logger = new XmlLogger();

}

public function retrieveFeed ($baseurl, $path) {$request = $this->client->setBaseUrl($baseurl)->get($path);$response = $request->send();if (200 != $response->getStatusCode()) {

$this->logger->log('Could not get: '.$host.$path);return null;

}

return $response->getBody();}// ...

}

What if we want unit tests to run fastwithout waiting for the network?

What if we ever want to

use a different HTTP client?

What if we want unit tests to run fastwithout logging?

What if we ever want to

use a different logger class?

What if we ever want to

use a different log format?

What if we want unit tests to run fastwithout logging?

Why is this classdifficult to unit test?

Page 27: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 27 www.php-schulung.de

<?phpuse Guzzle\Http\Client;use Acme\Logger\XmlLogger;

private $client;private $logger;

class FeedAggregator {__construct () {

$this->client = new Client();$this->logger = new XmlLogger();

}

public function retrieveFeed ($baseurl, $path) {$request = $this->client->setBaseUrl($baseurl)->get($path);$response = $request->send();if (200 != $response->getStatusCode()) {

$this->logger->log('Could not get: '.$host.$path);return null;

}

return $response->getBody();}// ...

}

What if we want unit tests to run fastwithout waiting for the network?

What if we ever want to

use a different HTTP client?

What if we want unit tests to run fastwithout logging?

What if we ever want to

use a different logger class?

What if we ever want to

use a different log format?

What if we want unit tests to run fastwithout logging?

Why is this classdifficult to unit test?

Dependencies are pulled.=> Replacing requires refactoring=> Dynamic replacing (only for

testing) is impossible

Page 28: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 28 www.php-schulung.de

<?phpuse Guzzle\Http\Client;use Acme\Logger\XmlLogger;

private $client;private $logger;

class FeedAggregator {__construct () {

$this->client = new Client();$this->logger = new XmlLogger();

}

public function retrieveFeed ($baseurl, $path) {$request = $this->client->setBaseUrl($baseurl)->get($path);$response = $request->send();if (200 != $response->getStatusCode()) {

$this->logger->log('Could not get: '.$host.$path);return null;

}

return $response->getBody();}// ...

}

Dependencies are pulled.

Page 29: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 29 www.php-schulung.de

<?phpuse Acme\Http\ClientInterface;use Acme\Logger\LoggerInterface;

private $client;private $logger;

class FeedAggregator {__construct (ClientInterface $client, LoggerInterface $logger) {

$this->client = $client;$this->logger = $logger;

}

public function retrieveFeed ($baseurl, $path) {$request = $this->client->setBaseUrl($baseurl)->get($path);$response = $request->send();if (200 != $response->getStatusCode()) {

$this->logger->log('Could not get: '.$host.$path);return null;

}

return $response->getBody();}// ...

}

Dependencies are pushed.

Page 30: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 30 www.php-schulung.de

<?phpuse Acme\Http\ClientInterface;use Acme\Logger\LoggerInterface;

private $client;private $logger;

class FeedAggregator {__construct (ClientInterface $client, LoggerInterface $logger) {

$this->client = $client;$this->logger = $logger;

}

public function retrieveFeed ($baseurl, $path) {$request = $this->client->setBaseUrl($baseurl)->get($path);$response = $request->send();if (200 != $response->getStatusCode()) {

$this->logger->log('Could not get: '.$host.$path);return null;

}

return $response->getBody();}// ...

}

Dependencies are pushed.

Class only dependson interfaces

Page 31: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 31 www.php-schulung.de

<?phpuse Acme\Http\ClientInterface;use Acme\Logger\LoggerInterface;

private $client;private $logger;

class FeedAggregator {__construct (ClientInterface $client, LoggerInterface $logger) {

$this->client = $client;$this->logger = $logger;

}

public function retrieveFeed ($baseurl, $path) {$request = $this->client->setBaseUrl($baseurl)->get($path);$response = $request->send();if (200 != $response->getStatusCode()) {

$this->logger->log('Could not get: '.$host.$path);return null;

}

return $response->getBody();}// ...

}

Dependencies are pushed.

Class only dependson interfaces

Implementations areProvided at runtimeImplementations areinjected at runtime

Page 32: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 32 www.php-schulung.de

<?phpuse Acme\Http\ClientInterface;use Acme\Logger\LoggerInterface;

private $client;private $logger;

class FeedAggregator {__construct (ClientInterface $client, LoggerInterface $logger) {

$this->client = $client;$this->logger = $logger;

}

public function retrieveFeed ($baseurl, $path) {$request = $this->client->setBaseUrl($baseurl)->get($path);$response = $request->send();if (200 != $response->getStatusCode()) {

$this->logger->log('Could not get: '.$host.$path);return null;

}

return $response->getBody();}// ...

}

Dependencies are pushed.

Class only dependson interfaces

Implementations areProvided at runtimeImplementations areinjected at runtime

Page 33: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 33 www.php-schulung.de

<?phpuse Acme\Http\ClientInterface;use Acme\Logger\LoggerInterface;

private $client;private $logger;

class FeedAggregator {__construct (ClientInterface $client, LoggerInterface $logger) {

$this->client = $client;$this->logger = $logger;

}

public function retrieveFeed ($baseurl, $path) {$request = $this->client->setBaseUrl($baseurl)->get($path);$response = $request->send();if (200 != $response->getStatusCode()) {

$this->logger->log('Could not get: '.$host.$path);return null;

}

return $response->getBody();}// ...

}

Dependencies are pushed.

Class only dependson interfaces

Implementations areProvided at runtimeImplementations areinjected at runtime

Easy to replace, evendynamically (for testing)

Easy to replace, evendynamically (for testing)

Page 34: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 34 www.php-schulung.de

<?phpuse Acme\Http\ClientInterface;use Acme\Logger\LoggerInterface;

private $client;private $logger;

class FeedAggregator {__construct (ClientInterface $client, LoggerInterface $logger) {

$this->client = $client;$this->logger = $logger;

}

public function retrieveFeed ($baseurl, $path) {$request = $this->client->setBaseUrl($baseurl)->get($path);$response = $request->send();if (200 != $response->getStatusCode()) {

$this->logger->log('Could not get: '.$host.$path);return null;

}

return $response->getBody();}// ...

}

Dependencies are pushed.

Class only dependson interfaces

Implementations areProvided at runtimeImplementations areinjected at runtime

Easy to replace, evendynamically (for testing)

Easy to replace, evendynamically (for testing)

On the level of the class,You are now experts for Dependency Injection.

Page 35: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 35 www.php-schulung.de

<?phpuse Acme\Http\ClientInterface;use Acme\Logger\LoggerInterface;

private $client;private $logger;

class FeedAggregator {__construct (ClientInterface $client, LoggerInterface $logger) {

$this->client = $client;$this->logger = $logger;

}

public function retrieveFeed ($baseurl, $path) {$request = $this->client->setBaseUrl($baseurl)->get($path);$response = $request->send();if (200 != $response->getStatusCode()) {

$this->logger->log('Could not get: '.$host.$path);return null;

}

return $response->getBody();}// ...

}

Dependencies are pushed.

Class only dependson interfaces

Implementations areProvided at runtimeImplementations areinjected at runtime

Easy to replace, evendynamically (for testing)

Easy to replace, evendynamically (for testing)

On the level of the class,You are now experts for Dependency Injection.

Any questions?

Page 36: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 36 www.php-schulung.de

<?phpuse Acme\Http\ClientInterface;use Acme\Logger\LoggerInterface;

private $client;private $logger;

class FeedAggregator {__construct (ClientInterface $client, LoggerInterface $logger) {

$this->client = $client;$this->logger = $logger;

}

public function retrieveFeed ($baseurl, $path) {$request = $this->client->setBaseUrl($baseurl)->get($path);$response = $request->send();if (200 != $response->getStatusCode()) {

$this->logger->log('Could not get: '.$host.$path);return null;

}

return $response->getBody();}// ...

}

Dependencies are pushed.

Class only dependson interfaces

Implementations areProvided at runtimeImplementations areinjected at runtime

Easy to replace, evendynamically (for testing)

Easy to replace, evendynamically (for testing)

On the level of the class,You are now experts for Dependency Injection.

Who constructsand pushes all the

dependencies?

Page 37: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 37 www.php-schulung.de

Page 38: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 38 www.php-schulung.de

Dependency Injection Container

DIC

“DI Container”, “DIC”, “Service Container”, “the Container”

Page 39: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 39 www.php-schulung.de

Page 40: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 40 www.php-schulung.de

Very Many Frameworks support Dependency Injection

Page 41: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 41 www.php-schulung.de

Structure of this presentation

● Why do we want Dependency Injection?● Code example: DI for generic PHP classes● Code example: DI in Symfony 2 You are here

Page 42: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 42 www.php-schulung.de

DI ist very easy in Symfony 2

Page 43: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 43 www.php-schulung.de

DI ist very easy in Symfony 2

● Any ordinary PHP class can be managed by DIC● Only 2 lines of configuration per class are needed● Any class managed by the DIC is called a “Service”

Page 44: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 44 www.php-schulung.de

# app/config/config.yml# ...services: my_service: class: Acme\MyBundle\Service\AwesomeClass

DI ist very easy in Symfony 2

● Any ordinary PHP class can be managed by DIC● Only 2 lines of configuration per class are needed● Any class managed by the DIC is called a “Service”

Page 45: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 45 www.php-schulung.de

# app/config/config.yml# ...services: my_service: class: Acme\MyBundle\Service\AwesomeClass

DI ist very easy in Symfony 2

● Any ordinary PHP class can be managed by DIC● Only 2 lines of configuration per class are needed● Any class managed by the DIC is called a “Service”

Class to manage

Name of the new service

Page 46: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 46 www.php-schulung.de

# php app/console container:debug

Page 47: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 47 www.php-schulung.de

# app/config/config.yml# ...services: my_service: class: Acme\MyBundle\Service\AwesomeClass

DI ist very easy in Symfony 2

● Any ordinary PHP class can be managed by DIC● Only 2 lines of configuration per class are needed● Any class managed by the DIC is called a “Service”

Page 48: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 48 www.php-schulung.de

# app/config/config.yml# ...services: my_service: class: Acme\MyBundle\Service\AwesomeClass arguments: some_arg: “string” another:

- arry_member - arry_member

even_more: @another_service

DI ist very easy in Symfony 2

● Any ordinary PHP class can be managed by DIC● Only 2 lines of configuration per class are needed● Any class managed by the DIC is called a “Service”

Page 49: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 49 www.php-schulung.de

# app/config/config.yml# ...services: my_service: class: Acme\MyBundle\Service\AwesomeClass arguments: some_arg: “string” another:

- arry_member - arry_member

even_more: @another_service

DI ist very easy in Symfony 2

● Any ordinary PHP class can be managed by DIC● Only 2 lines of configuration per class are needed● Any class managed by the DIC is called a “Service”

Any other servicecan be injected as

as argument

Arguments can bestrings, numbers,

arrays, placeholders,and many more ...

Page 50: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 50 www.php-schulung.de

<?php// src/Acme/FeedBundle/Service/FeedAggregator.php

use Acme\Http\ClientInterface;use Acme\Logger\LoggerInterface;

private $client;private $logger;

class FeedAggregator {__construct (ClientInterface $client, LoggerInterface $logger) {

$this->client = $client;$this->logger = $logger;

}

public function retrieveFeed ($baseurl, $path) {$request = $this->client->setBaseUrl($baseurl)->get($path);$response = $request->send();if (200 != $response->getStatusCode()) {

$this->logger->log('Could not get: '.$host.$path);return null;

}

return $response->getBody();}// ...

}

Page 51: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 51 www.php-schulung.de

<?php// src/Acme/FeedBundle/Service/FeedAggregator.php

use Acme\Http\ClientInterface;use Acme\Logger\LoggerInterface;

private $client;private $logger;

class FeedAggregator {__construct (ClientInterface $client, LoggerInterface $logger) {

$this->client = $client;$this->logger = $logger;

}

public function retrieveFeed ($baseurl, $path) {$request = $this->client->setBaseUrl($baseurl)->get($path);$response = $request->send();if (200 != $response->getStatusCode()) {

$this->logger->log('Could not get: '.$host.$path);return null;

}

return $response->getBody();}// ...

}

Page 52: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 52 www.php-schulung.de

# app/config/config.yml# ...services: feed_aggregator: class: Acme\FeedBundle\Service\FeedAggregator arguments: client: @http_client logger: @logger

<?php// src/Acme/FeedBundle/Service/FeedAggregator.php

use Acme\Http\ClientInterface;use Acme\Logger\LoggerInterface;

private $client;private $logger;

class FeedAggregator {__construct (ClientInterface $client, LoggerInterface $logger) {

$this->client = $client;$this->logger = $logger;

}

public function retrieveFeed ($baseurl, $path) {$request = $this->client->setBaseUrl($baseurl)->get($path);$response = $request->send();if (200 != $response->getStatusCode()) {

$this->logger->log('Could not get: '.$host.$path);return null;

}

return $response->getBody();}// ...

}

Page 53: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 53 www.php-schulung.de

# app/config/config.yml# ...services: feed_aggregator: class: Acme\FeedBundle\Service\FeedAggregator arguments: client: @http_client logger: @logger

<?php// src/Acme/FeedBundle/Service/FeedAggregator.php

use Acme\Http\ClientInterface;use Acme\Logger\LoggerInterface;

private $client;private $logger;

class FeedAggregator {__construct (ClientInterface $client, LoggerInterface $logger) {

$this->client = $client;$this->logger = $logger;

}

public function retrieveFeed ($baseurl, $path) {$request = $this->client->setBaseUrl($baseurl)->get($path);$response = $request->send();if (200 != $response->getStatusCode()) {

$this->logger->log('Could not get: '.$host.$path);return null;

}

return $response->getBody();}// ...

}

Page 54: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 54 www.php-schulung.de

Different Config for Testing?

● app/config/config.yml● app/config/config_dev.yml● app/config/config_test.yml Put it here here

Page 55: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 55 www.php-schulung.de

Dependency Injection Container

DIC

Instanziiert, konfiguriert und verwaltet alle Serviceklassen

Page 56: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 56 www.php-schulung.de

Dependency Injection Container

DIC

Instanziiert, konfiguriert und verwaltet alle Serviceklassen

DoctrineSwiftmailer

Our OwnServiceX

Page 57: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 57 www.php-schulung.de

Dependency Injection Container

DIC

DoctrineSwiftmailer

Instanziiert, konfiguriert und verwaltet alle Serviceklassen

Default: Nur 1 Instanz pro Service Klasse Default: Nur 1 Instanz pro Service Klasse Default: Nur 1 Instanz pro Service Klasse

Our OwnServiceX

Page 58: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 58 www.php-schulung.de

Sol-r Server

Elastic SearchServer

GenerischerWebservice

Geschäftslogik

Datenbank

Model-Schicht

Page 59: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 59 www.php-schulung.de

Sol-r Server

Elastic SearchServer

GenerischerWebservice

Geschäftslogik

DoctrineBundle

Datenbank

DoctrineService

Model-Schicht

Page 60: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 60 www.php-schulung.de

Sol-r Server

Elastic SearchServer

GenerischerWebservice

Sol-r Bundle

Client LibrarySol-r

Geschäftslogik

DoctrineBundle

Datenbank

Search ServiceDoctrineService

Model-Schicht

Page 61: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 61 www.php-schulung.de

Sol-r Server

Elastic SearchServer

GenerischerWebservice

Sol-r Bundle Elastic Search Bundle

Client LibrarySol-r

Client LibraryElastic Search

Geschäftslogik

DoctrineBundle

Datenbank

Search Service Search ServiceDoctrineService

Model-Schicht

Page 62: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 62 www.php-schulung.de

Sol-r Server

Elastic SearchServer

GenerischerWebservice

Sol-r Bundle Elastic Search Bundle

GuzzleBundle

Client LibrarySol-r

Client LibraryElastic Search

GuzzleHTTP Client

Geschäftslogik

DoctrineBundle

Datenbank

Search Service Search Service Generic ServiceDoctrineService

Model-Schicht

Page 63: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 63 www.php-schulung.de

Sol-r Server

Elastic SearchServer

GenerischerWebservice

Sol-r Bundle Elastic Search Bundle

GuzzleBundle

Client LibrarySol-r

Client LibraryElastic Search

GuzzleHTTP Client

Geschäftslogik

DoctrineBundle

Datenbank

Search Service Search Service Generic ServiceDoctrineService

Model-Schicht

Page 64: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 64 www.php-schulung.de

Sol-r Server

Elastic SearchServer

GenerischerWebservice

Sol-r Bundle Elastic Search Bundle

GuzzleBundle

Client LibrarySol-r

Client LibraryElastic Search

GuzzleHTTP Client

Geschäftslogik

DoctrineBundle

Datenbank

Search Service Search Service Generic ServiceDoctrineService

Model-Schicht

KomplexerService 1

KomplexerService 2

Page 65: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 65 www.php-schulung.de

Sol-r Server

Elastic SearchServer

GenerischerWebservice

Sol-r Bundle Elastic Search Bundle

GuzzleBundle

Client LibrarySol-r

Client LibraryElastic Search

GuzzleHTTP Client

Geschäftslogik

DoctrineBundle

Datenbank

Search Service Search Service Generic ServiceDoctrineService

Model-Schicht

KomplexerService 1

KomplexerService 2

Zugangsdaten?

Zugangsdaten?

Zugangsdaten?

Zugangsdaten?

Page 66: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 66 www.php-schulung.de

Sol-r Server

Elastic SearchServer

GenerischerWebservice

Sol-r Bundle Elastic Search Bundle

GuzzleBundle

Client LibrarySol-r

Client LibraryElastic Search

GuzzleHTTP Client

Geschäftslogik

DoctrineBundle

Datenbank

Search Service Search Service Generic ServiceDoctrineService

Model-Schicht

KomplexerService 1

KomplexerService 2

Zugangsdaten?

Zugangsdaten?

Zugangsdaten?

Zugangsdaten?

Braucht RAM, Instanziierung

kostet Zeit

Zugangsdaten?

Und soweiter ...

Page 67: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 67 www.php-schulung.de

Sol-r Server

Elastic SearchServer

GenerischerWebservice

Sol-r Bundle Elastic Search Bundle

GuzzleBundle

Client LibrarySol-r

Client LibraryElastic Search

GuzzleHTTP Client

Geschäftslogik

DoctrineBundle

Datenbank

Search Service Search Service Generic ServiceDoctrineService

Model-Schicht

KomplexerService 1

KomplexerService 2

DependencyInjectionContainer

Page 68: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 68 www.php-schulung.de

DIC und Performance

● Kompilierter Container:app/cache/dev/appDevDebugProjectContainer.php

app/cache/prod/appProdProjectContainer.php

Page 69: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 69 www.php-schulung.de

Sol-r Server

Elastic SearchServer

GenerischerWebservice

Sol-r Bundle Elastic Search Bundle

GuzzleBundle

Client LibrarySol-r

Client LibraryElastic Search

GuzzleHTTP Client

Geschäftslogik

DoctrineBundle

Datenbank

Search Service Search Service Generic ServiceDoctrineService

Model-Schicht

KomplexerService 1

KomplexerService 2

DependencyInjectionContainer

Page 70: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 70 www.php-schulung.de

Sol-r Server

Elastic SearchServer

GenerischerWebservice

Sol-r Bundle Elastic Search Bundle

GuzzleBundle

Client LibrarySol-r

Client LibraryElastic Search

GuzzleHTTP Client

Geschäftslogik

DoctrineBundle

Datenbank

Search Service Search Service Generic ServiceDoctrineService

Model-Schicht

KomplexerService 1

KomplexerService 2

DependecyInjectionContainer

Danke APC:

Byte-Code im

RAM

Page 71: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 71 www.php-schulung.de

Summary

● Our classes only depend on interfaces● All implementation classes are instanciated and

provided (injected) by the DIC● Our classes create only value objects and

exceptions● The DIC is not passed to any model / value class● Controllers can access the DIC to obtain services

Page 72: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 72 www.php-schulung.de

Further Reading

● http://fabien.potencier.org/article/11/what-is-dependency-injection

● http://symfony.com/doc/current/components/dependency_injection/compilation.html

● http://symfony.com/doc/current/cookbook/service_container/compiler_passes.html

● Use the source ...

Page 73: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 73 www.php-schulung.de

Thank you very much for your attention!

Page 74: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 74 www.php-schulung.de

Questions? Ideas, wishes, suggestions?

I'm ready to support Your Project!● Developer & Consultant: PHP, Symfony 2 etc.

– www.php-entwickler-berlin.de

● Trainer & Coach: Symfony 2 workshops 1-5 days– www.php-schulung.de

Page 75: Dependency Injection DI - bephpug.de · Timon Schroeter 4 Dependency Injection in a Nutshell software design pattern push (instead of pull) dependencies loose coupling easy testing

Timon Schroeter 75 www.php-schulung.de

SOLID

● S Single Responsibility Principle● O Open / Close Principle● L Liskov Substitution Principle● I Interface Segregation Principle● D Dependency Inversion Principle