Type Hinting with Interfaces
Part of the Object Oriented Programming section of Coddy's PHP journey — lesson 31 of 91.
One of the most powerful uses of interfaces is type hinting. When you use an interface as a type hint in a function or method parameter, you're saying "this function accepts any object that implements this interface." This makes your code flexible and reusable.
<?php
interface Playable {
public function play();
}
class Song implements Playable {
public function play() {
return "Playing song";
}
}
class Video implements Playable {
public function play() {
return "Playing video";
}
}
function startMedia(Playable $media) {
return $media->play();
}
$song = new Song();
$video = new Video();
echo startMedia($song) . "\n";
echo startMedia($video);
Output:
Playing song
Playing videoThe startMedia() function doesn't care whether it receives a Song or Video. It only cares that the object implements Playable and therefore has a play() method. This is the essence of programming to an interface rather than a concrete implementation.
You can also use interface type hints for return types:
<?php
function createMedia(string $type): Playable {
if ($type === "song") {
return new Song();
}
return new Video();
}
This guarantees the function always returns something that implements Playable, regardless of the specific class.
Key Point: Type hinting with interfaces lets you write functions that work with any class implementing that interface, making your code more flexible and easier to extend.
Challenge
EasyLet's build a document processing system that demonstrates the power of type hinting with interfaces. You'll create a function that can process any document type — as long as it implements the right interface, your function will work with it seamlessly.
You'll organize your code across four files:
Exportable.php— Define anExportableinterface with a single method signature:export(). Any class implementing this interface promises it can export its content in some format.Report.php— Create aReportclass that implementsExportable. Include the interface file. The class should have a private$titleproperty and a private$dataproperty. The constructor accepts both values. Implementexport()to return"Report: [title] - [data]".Invoice.php— Create anInvoiceclass that also implementsExportable. Include the interface file. The class should have a private$invoiceNumberproperty and a private$amountproperty. The constructor accepts both values. Implementexport()to return"Invoice #[invoiceNumber]: $[amount]".main.php— Include both the Report and Invoice files. Create a function calledprocessDocumentthat accepts anExportableparameter and returns the result of callingexport()on it. This function uses interface type hinting — it works with any object that implementsExportable.
You'll receive four inputs: a report title, report data, an invoice number, and an invoice amount. Create a Report and an Invoice with these values. Pass each one to your processDocument() function and print the results — the report first, then the invoice, each on its own line.
The beauty of this approach is that processDocument() doesn't know or care whether it's handling a Report or an Invoice. It only knows the object can be exported — that's the contract the interface guarantees.
Try it yourself
<?php
// Include the class files
require_once 'Report.php';
require_once 'Invoice.php';
// Read inputs
$reportTitle = trim(fgets(STDIN));
$reportData = trim(fgets(STDIN));
$invoiceNumber = trim(fgets(STDIN));
$invoiceAmount = trim(fgets(STDIN));
// TODO: Create a function called processDocument
// - It should accept an Exportable parameter (use type hinting)
// - It should return the result of calling export() on the parameter
// TODO: Create a Report object with the report title and data
// TODO: Create an Invoice object with the invoice number and amount
// TODO: Pass each object to processDocument() and print the results
// Print the report result first, then the invoice result (each on its own line)
?>This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesIntroduction to OOPClasses vs ObjectsThe $this KeywordMethodsPropertiesConstructor (__construct)Destructor (__destruct)Recap - Simple Calculator4Inheritance
Basic InheritanceThe parent:: KeywordMethod OverridingThe final KeywordAbstract ClassesRecap - Employee Hierarchy7Encapsulation
Public, Protected, PrivateAccess Modifiers in DepthGetters and SettersInformation HidingConstructor Promotion (8.0)Recap - Student Records System2Namespaces & Autoloading
Introduction to NamespacesThe use KeywordPSR-4 Autoloading StandardComposer AutoloaderRecap - Organized Project5Interfaces & Contracts
Introduction to InterfacesImplementing InterfacesMultiple Interface ImplementInterface vs Abstract ClassType Hinting with InterfacesRecap - Shape Calculator8Magic Methods
Magic Methods Introduction__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Object Cloning__serialize & __unserializeRecap - Custom Collection11Type System & Error Handling
Type DeclarationsNullable TypesUnion & Intersection TypesException ClassesCustom Exception HierarchyTry, Catch, FinallyRecap - Form Validator14Project: Library Management
Project OverviewBook and User Classes3Class Properties
Instance vs Static PropertiesConstants in ClassesStatic Methods & PropertiesPrivate & Protected PropertiesReadonly Properties (PHP 8.1)Recap - Bank Account Manager6Polymorphism
Method Overriding RevisitedPolymorphism via InterfacesType Hinting & Union TypesLate Static BindingRecap - Payment Processor9Traits
Introduction to TraitsUsing Multiple TraitsTrait Conflict ResolutionAbstract Methods in TraitsTraits vs Inheritance12Design Patterns Part 1
Intro to Design PatternsSingleton PatternFactory PatternObserver PatternStrategy Pattern