Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Managing Dependencies in PHP

Managing Dependencies in PHP

Managing how classes depend on each other is an important aspect of building software. If you know how to manage dependencies then writing maintainable and testable code becomes easier. In this talk we’ll go over how to manage a third party and internal dependencies using interfaces, dependency injection, and an inversion of control container.

Avatar for Nick Escobedo

Nick Escobedo

March 11, 2019

Other Decks in Programming

Transcript

  1. WHAT WE’LL GO OVER ▸ How to identify dependencies ▸

    Managing dependencies ▸ Interfaces ▸ Dependency Injection ▸ Inversion of Control Containers (IoC Container)
  2. INITIAL TWO FACTOR CLASS <?php class TwoFactor { public function

    sendCode(string $phoneNumber) { try { $twilioClient = new Twilio('api-key'); $response = $twilioClient->sendSms( $phoneNumber, 'Your two factor code is: ' . rand(100000, 999999) ); } catch (Exception $e) { return false; } return $response->messageSentSuccessfully(); } } TwoFactor Twilio
  3. TWO FACTOR W/ ENVIRONMENT CHECK TwoFactor Twilio <?php class TwoFactor

    { public function sendCode(string $phoneNumber, string $environment): bool { if ($environment != 'prod') { return true; } try { $twilioClient = new Twilio('api-key'); $response = $twilioClient->sendSms( $phoneNumber, 'Your two factor code is: ' . rand(100000, 999999) ); } catch (Exception $e) { return false; } return $response->messageSentSuccessfully(); } }
  4. public function testReturnsTrueForSuccessfulTextMessage { $twoFactor = new TwoFactor(); $output =

    $twoFactor->sendCode('1234567890', 'prod') $this->assertTrue($output); } TEST
  5. “IN COMPUTING, AN INTERFACE IS A SHARED BOUNDARY ACROSS WHICH

    TWO OR MORE SEPARATE COMPONENTS OF A COMPUTER SYSTEM EXCHANGE INFORMATION.” https://en.wikipedia.org/wiki/Interface_(computing)
  6. WHAT IS AN INTERFACE? ▸ Defines the methods that must

    exist in a class ▸ Defines inputs* ▸ Defines outputs* ▸ Creates a boundary between a higher and lower level classes
  7. WHY USE AN INTERFACE? ▸ Self documenting ▸ Shows intent

    ▸ Less bugs* ▸ Standardization ▸ IDEs ▸ Manages dependencies
  8. TWO FACTOR W/ ENVIRONMENT CHECK <?php class TwoFactor { public

    function sendCode(string $phoneNumber, string $environment): bool { if ($environment != 'prod') { return true; } try { $twilioClient = new Twilio('api-key'); $response = $twilioClient->sendSms( $phoneNumber, 'Your two factor code is: ' . rand(100000, 999999) ); } catch (Exception $e) { return false; } return $response->messageSentSuccessfully(); } }
  9. TWO FACTOR W/ ENVIRONMENT CHECK TwoFactor Twilio <?php class TwoFactor

    { public function sendCode(string $phoneNumber, string $environment): bool { if ($environment != 'prod') { return true; } try { $twilioClient = new Twilio('api-key'); $response = $twilioClient->sendSms( $phoneNumber, 'Your two factor code is: ' . rand(100000, 999999) ); } catch (Exception $e) { return false; } return $response->messageSentSuccessfully(); } }
  10. IMPLEMENT THE INTERFACE <?php class TwilioTextMessage implements TextMessageInterface { public

    function send(string $phoneNumber, string $message): bool { try { $twilioClient = new Twilio('api-key'); $response = $twilioClient->sendSms($phoneNumber, $message); } catch (Exception $e) { return false; } return $response->messageSentSuccessfully(); } } TwilioTextMessage Twilio
  11. USE NEW CLASS TwoFactor TwilioTextMessage <?php class TwoFactor { public

    function sendCode(string $phoneNumber, string $environment) { if ($environment != 'prod') { return true; } $twilioClient = new TwilioTextMessage(); $response = $twilioClient->send( $phoneNumber, 'Your two factor code is: ' . rand(100000, 999999) ); return $response; } }
  12. IMPLEMENT THE INTERFACE (AGAIN) <?php class LogTextMessage implements TextMessageInterface {

    public function send(string $phoneNumber, string $message): bool { $log = new Logger(); $log->info('Sending text message.'); $log->info('Phone: ' . $phoneNumber); $log->info('Message: ' . $message); return true; } } LogTextMessage Logger
  13. <?php class LogTextMessage implements TextMessageInterface { public function send(string $phoneNumber,

    string $message): bool { $log = new Logger(); $log->info('Sending text message.'); $log->info('Phone: ' . $phoneNumber); $log->info('Message: ' . $message); return true; } } <?php class TwilioTextMessage implements TextMessageInterface { public function send(string $phoneNumber, string $message): bool { try { $twilioClient = new Twilio('api-key'); $response = $twilioClient->sendSms($phoneNumber, $message); } catch (Exception $e) { return false; } return $response->messageSentSuccessfully(); } }
  14. TwoFactor TwilioTextMessage <?php class TwoFactor { public function sendCode(string $phoneNumber,

    string $environment) { if ($environment != 'prod') { return true; } $twilioClient = new TwilioTextMessage(); $response = $twilioClient->send( $phoneNumber, 'Your two factor code is: ' . rand(100000, 999999) ); return $response; } }
  15. PREVIOUS TWO FACTOR CLASS <?php class TwoFactor { public function

    sendCode(string $phoneNumber, string $environment) { if ($environment != 'prod') { return true; } $twilioClient = new TwilioTextMessage(); $response = $twilioClient->send( $phoneNumber, 'Your two factor code is: ' . rand(100000, 999999) ); return $response; } }
  16. TWO FACTOR WITH DEPENDENCY INJECTION TwoFactor TwilioTextMessage <?php class TwoFactor

    { private $textMessage; public function __construct(TwilioTextMessage $textMessage) { $this->textMessage = $textMessage; } public function sendCode(string $phoneNumber, string $environment) { if ($environment != 'prod') { return true; } $response = $this->textMessage->send( $phoneNumber, 'Your two factor code is: ' . rand(100000, 999999) ); return $response; } }
  17. PREVIOUS TWILIO IMPLEMENTATION <?php class TwilioTextMessage implements TextMessageInterface { public

    function send(string $phoneNumber, string $message): bool { try { $twilioClient = new Twilio('api-key'); $response = $twilioClient->sendSms($phoneNumber, $message); } catch (Exception $e) { return false; } return $response->messageSentSuccessfully(); } } TwilioTextMessage Twilio
  18. TWILIO IMPLEMENTATION WITH DI <?php class TwilioTextMessage implements TextMessageInterface {

    private $twilio; public function __construct(Twilio $twilio) { $this->twilio = $twilio; } public function send(string $phoneNumber, string $message): bool { try { $response = $this->twilio->sendSms($phoneNumber, $message); } catch (Exception $e) { return false; } return $response->messageSentSuccessfully(); } }
  19. TWILIO IMPLEMENTATION TEST public function testReturnsFalseOnException { $twilio = Mockery::mock(Twilio::class);

    $twilio->shouldReceive('sendSms')->andThrow(Exception); $twilioTextMessage = new TwilioTextMessage($twilio); $output = $twilioTextMessage->send('1234567890', 'Yay messages!!! :)'); $this->assertFalse($output); }
  20. PREVIOUS LOGGER IMPLEMENTATION <?php class LogTextMessage implements TextMessageInterface { public

    function send(string $phoneNumber, string $message): bool { $log = new Logger(); $log->info('Sending text message.'); $log->info('Phone: ' . $phoneNumber); $log->info('Message: ' . $message); return true; } }
  21. LOGGER IMPLEMENTATION WITH DI LogTextMessage Logger <?php class LogTextMessage implements

    TextMessageInterface { private $logger; public function __construct(Logger $logger) { $this->logger = $logger; } public function send(string $phoneNumber, string $message): bool { $this->logger->info('Sending text message.'); $this->logger->info('Phone: ' . $phoneNumber); $this->logger->info('Message: ' . $message); return true; } }
  22. DEPENDENCY INJECTION WITH INTERFACE <?php class TwoFactor { private $textMessage;

    public function __construct(TextMessageInterface $textMessage) { $this->textMessage = $textMessage; } public function sendCode(string $phoneNumber) { $response = $this->textMessage->send( $phoneNumber, 'Your two factor code is: ' . rand(100000, 999999) ); return $response; } } TwoFactor TextMessageInterface
  23. CONFIGURE CONTAINER <?php $this->app->bind(TwilioTextMessage::class, function ($app) { return new TwilioTextMessage('api-key');

    }); $this->app->bind(TextMessageInterface::class, function ($app) { if ($environment == 'prod') { return $app->make(TwilioTextMessage::class); } return $app->make(LogTextMessage::class); });
  24. TWO FACTOR WITH DEPENDENCY INJECTION <?php class TwoFactor { private

    $textMessage; public function __construct(TextMessageInterface $textMessage) { $this->textMessage = $textMessage; } public function sendCode(string $phoneNumber) { $response = $this->textMessage->send( $phoneNumber, 'Your two factor code is: ' . rand(100000, 999999) ); return $response; } }
  25. DEPENDENCY TREE <?php class TwoFactor { private $textMessage; public function

    __construct(TextMessageInterface $textMessage) { $this->textMessage = $textMessage; } public function sendCode(string $phoneNumber) { $response = $this->textMessage->send( $phoneNumber, 'Your two factor code is: ' . rand(100000, 999999) ); return $response; } } TwoFactor TextMessageInterface TwilioTextMessage LogTextMessage
  26. TWO FACTOR TEST public function testReturnsTrueForSuccessfulTextMessage { $textMessage = Mockery::mock(TextMessageInterface::class);

    $textMessage->shouldReceive('send')->andReturn(true); $twoFactor = new TwoFactor($textMessage); $response = $twoFactor->sendCode('1234567890') $this->assertTrue($response) }