Adapter pattern is used to convert the interface of a class to another interface, so that the existing class can be adapted to the desired new behavior. This way an existing class can adapt to a new functionality with any direct change to it.
Sometimes we want to use some existing class(es), for some functionality, but the interface of the classes does not match with the new requirement. Adapter pattern is used in that case.
NOTES
In this article, we discuss the implementation of the Adapter Pattern in PHP.
See the Adapter in other languages in the “Other Code Implementations” section. Or, use the link below to check the details of the Adapter Pattern-
Implementation
Follow the steps below to implement the Adapter pattern in PHP-
Prerequisite-
- We want to adapt an existing interface to some new behavior of a new interface.
- A new interface, to which the existing interface will adapt to.
To implement an adapter we need to follow the steps below-
- Create an adapter class.
- Implement the new interface for the adapter class.
- In the adapter declare a filed of type of the existing(old) interface. And in the constructor accept and set the object of existing(old) class(implementing old interface).
- In the implementations of the adapter, use/call methods from the old interface object, and use the functionality whenever required.
Here is a simple Adapter pattern implementation in PHP-
<?php
// Adapter pattern implementation in PHP
// Old interface
interface OldInterface {
function operation1(): void;
function operation2(): void;
}
// Old interface implementation
class OldExample implements OldInterface {
public function operation1(): void {
echo "Operation 1 of Old Examplen";
}
public function operation2(): void {
echo "Operation 2 of Old Examplen";
}
}
// New interface
interface NewInterface {
function newOperation1(): void;
function newOperation2(): void;
function newOperation3(): void;
}
// New interface implementation
class NewExample implements NewInterface {
public function newOperation1(): void {
echo "New Operation 1 of New Examplen";
}
public function newOperation2(): void {
echo "New Operation 2 of New Examplen";
}
public function newOperation3(): void {
echo "New Operation 3 of New Examplen";
}
}
// Adapter
class Adapter implements NewInterface {
private OldInterface $oldInterface;
public function __construct(OldInterface $oldInterface) {
$this->oldInterface = $oldInterface;
}
public function newOperation1(): void {
echo "Inside New Operation 1 of Adaptern";
$this->oldInterface->operation1();
}
public function newOperation2(): void {
echo "Inside New Operation 2 of Adaptern";
$this->oldInterface->operation2();
}
public function newOperation3(): void {
throw new Exception("Operation not available in Adapter");
}
}
// Demo
$oldExample = new OldExample();
$adapter = new Adapter($oldExample);
$adapter->newOperation1();
$adapter->newOperation2();
PHPThis will generate following output.
Inside New Operation 1 of Adapter
Operation 1 of Old Example
Inside New Operation 2 of Adapter
Operation 2 of Old Example
PlaintextExamples
Here are a few examples of Adapter pattern in PHP.
Example #1: API with File Adapter
Pre-existing Interface
We have an interface and its implementation that performs file operations (read/write etc.). The interface name is “FileOp” and the implementation is “FileOperation“.
New Requirement/Changes
Later we created an interface for API, named “Api“. There are implementations of the “Api” interface – “NativeApi“, and “ThirdPartyApi“.
Adapter Requirement
We want the file operations to behave like the API interface, for ease of use. So that the client/user does not realize any difference while performing a native or 3rd party API call, and file operations.
Let’s start the implementation-
File Interface
- Create a file “FileOp.php”.
- Create interface “FileOp”.
- Declare methods for file operations, here we have methods – “readFile”, “writeFile”.
<?php
// FileOp.php
namespace BigBoxCodeDesignPatternAdapterFileAdapter;
interface FileOp {
function readFile(): string;
function writeFile(string $input): void;
}
PHPFileOperation Class [implements File Interface]
- Create a file “FileOperation.php”.
- Create class “FileOperation”.
- Implement “FileOp” interface for the class. Define method “readFile” and “writeFile” as part of the interface implementation.
<?php
// FileOperation
namespace BigBoxCodeDesignPatternAdapterFileAdapter;
class FileOperation implements FileOp {
public function readFile(): string {
echo "Reading from filen";
return "some dummy response read from file";
}
public function writeFile(string $input): void {
echo "Writing to file: " . $input . "n";
}
}
PHPAPI Interface
- Create a file “Api.php”.
- Define interface “Api”.
- Declare methods – “fetchData”, “sendData”.
<?php
// Api.php
namespace BigBoxCodeDesignPatternAdapterFileAdapter;
interface Api {
function fetchData(): string;
function sendData(string $data): void;
}
PHPNative API Class [implements Api interface]
- Create a file “NativeApi.php”.
- Create class “NativeApi”.
- Implement “Api” interface. Define methods “fetchData” and “sendData”.
<?php
// NativeApi.php
namespace BigBoxCodeDesignPatternAdapterFileAdapter;
class NativeApi implements Api {
public function fetchData(): string {
echo "Fetching data from Native APIn";
return "Data read from Native Api";
}
public function sendData(string $data): void {
echo "Sending data to Native API: " . $data . "n";
}
}
PHPThird-Party API Class [implements Api interface]
- Create a file “ThirdPartyApi.php”.
- Create class “ThirdPartyApi”.
- Implement interface “Api” for the class.
<?php
// ThirdPartyApi.php
namespace BigBoxCodeDesignPatternAdapterFileAdapter;
class ThirdPartyApi implements Api {
public function fetchData(): string {
echo "Fetching data from Third Party APIn";
return "Data read from Third Party Api";
}
public function sendData(string $data): void {
echo "Sending data to Third Party API: " . $data . "n";
}
}
PHPTo adapt to the API interface, let’s create an adapter.
File Adapter
- Create file “FileAdapter.php”.
- Define class “FileAdapter”.
- Define a private property “$fileOp” of the interface “FileOp”. Accept a param in the constructor and set the value of “$fileOp”.
- Implement interface “Api” for “FileAdapter”. Define methods “fetchData” and “sendData” as part of the interface implementation.
- In the method implementations call/use methods of “$fileOp”, whenever required and/or possible.
<?php
// FileAdapter.php
namespace BigBoxCodeDesignPatternAdapterFileAdapter;
class FileAdapter implements Api {
public function __construct(private FileOp $fileOp) {
}
public function fetchData(): string {
return $this->fileOp->readFile();
}
public function sendData(string $data): void {
$this->fileOp->writeFile($data);
}
}
PHPDemo
In the client we have to create an object of the “FileOperation” class first, then we have to pass the “FileOperation” object to the “FileAdapter”. Then we can use the “FileAdpater” object just like other API classes, as it implements the “Api” interface.
<?php
// demo.php
require __DIR__ . '/../../vendor/autoload.php';
use BigBoxCodeDesignPatternAdapterFileAdapterFileAdapter;
use BigBoxCodeDesignPatternAdapterFileAdapterFileOperation;
use BigBoxCodeDesignPatternAdapterFileAdapterThirdPartyApi;
// make a call to third part API for testing
$thirdPartyApi = new ThirdPartyApi();
$thirdPartyApi->fetchData();
$thirdPartyApi->sendData("1234");
// Make a call to the file via FileAdapter
$file = new FileOperation();
$fileAdapter = new FileAdapter($file);
$fileAdapter->fetchData();
$fileAdapter->sendData("ABCDEF");
PHPOutput
Output will be as below
Fetching data from Third Party API
Sending data to Third Party API: 1234
Reading from file
Writing to file: ABCDEF
PlaintextExample #2: Transport
Pre-existing Interface
We have “Plane” and “Helicopter” classes that implement the “AirTransport” adapter.
New Requirement/Changes
Later we created a general “Transport” interface. And a few classes that implement the general “Transport” interface.
Adapter Requirement
We want the “AirTransport” interface to adapt to the new general “Transport” interface.
Let’s check the implementation-
AirTransport Interface
- Create file “AirTransport.php”.
- Define interface “AirTrasport”.
- Declare methods – “getNumberOfWheels”, “getNumberOfEngines”, “getWeight”, “getDistanceTravelled”, “getTravelCosTotal”.
<?php
// AirTransport.php
namespace BigBoxCodeDesignPatternAdapterTransportAdapter;
interface AirTransport {
public function getNumberOfWheels(): int;
public function getNumberOfEngines(): int;
public function getWeight(): float;
public function getDistanceTravelled(): float;
public function getTravelCostTotal(): float;
}
PHPPlane Class [implements AirTransport]
- Create file “Plane.php”.
- Define the class “Plane”.
- Implement “AirTransport” interface for the class.
<?php
// Plane.php
namespace BigBoxCodeDesignPatternAdapterTransportAdapter;
class Plane implements AirTransport {
public function getNumberOfWheels(): int {
return 3;
}
public function getNumberOfEngines(): int {
return 2;
}
public function getWeight(): float {
return 127_000;
}
public function getDistanceTravelled(): float {
return 500;
}
public function getTravelCostTotal(): float {
return 3_000;
}
}
PHPHelicopter Class [implements AirTransport]
- Create file “Helicopter.php”.
- Define class “Helicopter”.
- Implement “AirTransport” interface.
<?php
// Helicopter.php
namespace BigBoxCodeDesignPatternAdapterTransportAdapter;
class Helicopter implements AirTransport {
public function getNumberOfWheels(): int {
return 0;
}
public function getNumberOfEngines(): int {
return 1;
}
public function getWeight(): int {
return 12000;
}
public function getDistanceTravelled(): int {
return 180;
}
public function getTravelCostTotal(): int {
return 20000;
}
}
PHPHere is the new interface, an interface for transports in general-
Transport Interface
- Create file “Transport.php”.
- Define interface “Transport”.
- Declare methods – “getNumerOfWheels”, “getWeight”, “getDistanceTravelled”, “getTravelCosPerMile”.
<?php
// Transport.php
namespace BigBoxCodeDesignPatternAdapterTransportAdapter;
interface Transport {
public function getNumberOfWheels(): int;
public function getWeight(): float;
public function getDistanceTravelled(): float;
public function getTravelCostPerMile(): float;
}
PHPBus Class [implements Transport]
- Create file “Bus.php”.
- Create “Bus” class.
- Implement “Transport” interface for the “Bus” class.
<?php
// Bus.php
namespace BigBoxCodeDesignPatternAdapterTransportAdapter;
class Bus implements Transport {
public function getNumberOfWheels(): int {
return 4;
}
public function getWeight(): float {
return 10_000;
}
public function getDistanceTravelled(): float {
return 1_000;
}
public function getTravelCostPerMile(): float {
return 5;
}
}
PHPBike Class [implements Transport]
- Create file “Bike.php”.
- Create class “Bike” and implement the “Transport” interface for the class.
<?php
// Bike.php
namespace BigBoxCodeDesignPatternAdapterTransportAdapter;
class Bike implements Transport {
public function getNumberOfWheels(): int {
return 2;
}
public function getWeight(): float {
return 700;
}
public function getDistanceTravelled(): float {p
return 80;
}
public function getTravelCostPerMile(): float {
return 4;
}
}
PHPLet’s create the adapter now.
AirTransportAdapter Class [implements Transport]
- Create file “AirTransportAdapter.php”.
- Create class “AirTransportAdapter”.
- Declare a private property “$airTransport” of type of “AirTransport”.
- In the constructor accept and set the value of “$airTransport”.
- Implement “Transport” interface for the class.
- In the method implementations, use the methods from the “$airTransport” object.
<?php
// AirTransportAdapter.php
namespace BigBoxCodeDesignPatternAdapterTransportAdapter;
class AirTransportAdapter implements Transport {
public function __construct(private AirTransport $airTransport) {
$this->airTransport = $airTransport;
}
public function getNumberOfWheels(): int {
return $this->airTransport->getNumberOfWheels();
}
public function getWeight(): float {
return $this->airTransport->getWeight();
}
public function getDistanceTravelled(): float {
$distanceInNauticalMile = $this->airTransport->getDistanceTravelled();
return $distanceInNauticalMile * 1.151;
}
public function getTravelCostPerMile(): float {
$totalCost = $this->airTransport->getTravelCostTotal();
return $totalCost / $this->getDistanceTravelled();
}
}
PHPDemo
While creating an “AirTransportAdapter” object, we need to pass an object of the “Plane” or “Helicopter” (classes that implement the “AirTransport” interface). Then we can use the adapter object.
<?php
// demo.php
require __DIR__ . '/../../vendor/autoload.php';
use BigBoxCodeDesignPatternAdapterTransportAdapterAirTransportAdapter;
use BigBoxCodeDesignPatternAdapterTransportAdapterBus;
use BigBoxCodeDesignPatternAdapterTransportAdapterPlane;
echo "Get information of Bus travel...";
$bus = new Bus();
echo "nNumber of wheels: " . $bus->getNumberOfWheels();
echo "nWeight(kg): " . $bus->getWeight();
echo "nDistance(miles): " . $bus->getDistanceTravelled();
echo "nCost per mile: " . $bus->getTravelCostPerMile();
echo "nnGet information of Plane travel...";
$planeTransport = new AirTransportAdapter(new Plane());
echo "nNumber of wheels: " . $planeTransport->getNumberOfWheels();
echo "nWeight(kg): " . $planeTransport->getWeight();
echo "nDistance(miles): " . $planeTransport->getDistanceTravelled();
echo "nCost per mile: " . $planeTransport->getTravelCostPerMile();
PHPOutput
Output will be as below-
Get information of Bus travel...
Number of wheels: 4
Weight(kg): 10000
Distance(miles): 1000
Cost per mile: 5
Get information of Plane travel...
Number of wheels: 3
Weight(kg): 127000
Distance(miles): 575.5
Cost per mile: 5.2128583840139
PlaintextSource Code
Use the following link to get the source code:
Other Code Implementations
Use the following links to check Adapter pattern implementation in other programming languages.