<?php
class Facebook {
public function getUserToken($userId) {
// code to get user token
}
public function postUpdate($message) {
// code to post status update
}
}
class Twitter {
public function checkUserToken($userId) {
// code to get user token
}
public function setStatusUpdate($message) {
// code to post status update
}
}
interface iStatusUpdate {
function getUserToken($userId);
function postUpdate($message);
}
class TwitterAdapter implements iStatusUpdate {
protected $twitter;
public function __construct(Twitter $twitter){
$this->twitter = $twitter;
}
public function getUserToken($userId) {
$this->twitter->checkUserToken($userId);
}
public function postUpdate($message) {
$this->twitter->setStatusUpdate($message);
}
}
class SomeOtherServiceAdapter implements iStatusUpdate {
protected $otherService;
public function __construct(SomeOtherService $otherService){
$this->otherService = $otherService;
}
public function getUserToken($userId) {
$this->otherService->authenticate($userId);
}
public function postUpdate($message) {
$this->otherService->postMessage($message);
}
}
// USAGE
$statusUpdate = new TwitterAdapter(new Twitter);
$statusUpdate->getUserToken($someUserId);
$statusUpdate->postUpdate('some message');
// or
$statusUpdate = new SomeOtherServiceAdapter(new SomeOtherService);
$statusUpdate->getUserToken($someUserId);
$statusUpdate->postUpdate('some message');
<?php
interface Notification
{
public function send(string $title, string $message);
}
class EmailNotification implements Notification
{
private $adminEmail;
public function __construct(string $adminEmail)
{
$this->adminEmail = $adminEmail;
}
public function send(string $title, string $message): void
{
mail($this->adminEmail, $title, $message);
echo "Sent email with title '$title' to '{$this->adminEmail}' that says '$message'.";
}
}
class SlackNotification implements Notification
{
private $slack;
private $chatId;
public function __construct(SlackApi $slack, string $chatId)
{
$this->slack = $slack;
$this->chatId = $chatId;
}
/**
* An Adapter is not only capable of adapting interfaces, but it can also
* convert incoming data to the format required by the Adaptee.
*/
public function send(string $title, string $message): void
{
$slackMessage = "#" . $title . "# " . strip_tags($message);
$this->slack->logIn();
$this->slack->sendMessage($this->chatId, $slackMessage);
}
}
class SlackApi
{
private $login;
private $apiKey;
public function __construct(string $login, string $apiKey)
{
$this->login = $login;
$this->apiKey = $apiKey;
}
public function logIn(): void
{
// Send authentication request to Slack web service.
echo "Logged in to a slack account '{$this->login}'.\n";
}
public function sendMessage(string $chatId, string $message): void
{
// Send message post request to Slack web service.
echo "Posted following message into the '$chatId' chat: '$message'.\n";
}
}
// USAGE
function clientCode(Notification $notification)
{
// ...
echo $notification->send("Website is down!",
"<strong style='color:red;font-size: 50px;'>Alert!</strong> " .
"Our website is not responding. Call admins and bring it up!");
// ...
}
echo "Client code is designed correctly and works with email notifications:\n";
$notification = new EmailNotification("developers@example.com");
clientCode($notification);
echo "\n\n";
echo "The same client code can work with other classes via adapter:\n";
$slackApi = new SlackApi("example.com", "XXXXXXXX");
$notification = new SlackNotification($slackApi, "Example.com Developers");
clientCode($notification);
<?php
interface Book
{
public function turnPage();
public function open();
public function getPage(): int;
}
interface EBook
{
public function unlock();
public function pressNext();
/**
* returns current page and total number of pages, like [10, 100] is page 10 of 100
*
* @return int[]
*/
public function getPage(): array;
}
class PaperBook implements Book
{
private int $page;
public function open()
{
$this->page = 1;
}
public function turnPage()
{
$this->page++;
}
public function getPage(): int
{
return $this->page;
}
}
class Kindle implements EBook
{
private int $page = 1;
private int $totalPages = 100;
public function pressNext()
{
$this->page++;
}
public function unlock()
{
}
/**
* returns current page and total number of pages, like [10, 100] is page 10 of 100
*
* @return int[]
*/
public function getPage(): array
{
return [$this->page, $this->totalPages];
}
}
class EBookAdapter implements Book
{
protected EBook $eBook;
public function __construct(EBook $eBook)
{
$this->eBook = $eBook;
}
/**
* This class makes the proper translation from one interface to another.
*/
public function open()
{
$this->eBook->unlock();
}
public function turnPage()
{
$this->eBook->pressNext();
}
/**
* notice the adapted behavior here: EBook::getPage() will return two integers, but Book
* supports only a current page getter, so we adapt the behavior here
*/
public function getPage(): int
{
return $this->eBook->getPage()[0];
}
}
// USAGE
$book = new PaperBook();
$book->open();
$book->turnPage();
$kindle = new Kindle();
$book = new EBookAdapter($kindle);
$book->open();
$book->turnPage();
<?php
/**
* interface for creating render classes
*/
interface RenderTemplateInterface
{
public function renderHeader();
public function renderBody();
public function renderFooter();
}
/**
* Used for rendering HTML templates
*/
class RenderHTMLTemplate implements RenderTemplateInterface
{
public function renderHeader()
{
return "<html><body>";
}
public function renderBody()
{
return "Hello World";
}
public function renderFooter()
{
return "</body></html>";
}
}
/**
* Separate interface just for rendering PDF's
* Having a separate interface from RenderTemplateInterface could be a requirement from a third party
*/
interface PDFTemplateInterface
{
public function renderTop();
public function renderMiddle();
public function renderBottom();
}
/**
* Used for rendering PDF templates
*/
class RenderPDFTemplate implements PDFTemplateInterface
{
public function renderTop()
{
return "This is the top of the PDF";
}
public function renderMiddle()
{
return "Hello World";
}
public function renderBottom()
{
return "This is the bottom of the PDF";
}
}
/**
* The adapter - this will encapsulate an instance of the RenderPDFTemplate class
* to work polymorphically with the RenderTemplateInterface interface
*/
class PDFTemplateAdapter implements RenderTemplateInterface
{
private $pdfTemplate;
public function __construct(PDFTemplateInterface $pdfTemplate)
{
$this->pdfTemplate = $pdfTemplate;
}
public function renderHeader()
{
return $this->pdfTemplate->renderTop();
}
public function renderBody()
{
return $this->pdfTemplate->renderMiddle();
}
public function renderFooter()
{
return $this->pdfTemplate->renderBottom();
}
}
$pdfTemplate = new RenderPDFTemplate();
// $pdfTemplateAdapter will implement RenderTemplateInterface, just like RenderHTMLTemplate does
$pdfTemplateAdapter = new PDFTemplateAdapter($pdfTemplate);
// This is the top of the PDF
echo $pdfTemplateAdapter->renderHeader();