PHP / CHAPTER 09

Interfaces and replaceable collaborators

Advanced

Define behavior contracts that make services testable.

By the end of this chapter

  • Express required methods with an interface
  • Inject a collaborator rather than constructing it internally
  • Separate transformation from external effects

The idea

An interface names a behavior contract through method signatures. Different classes can implement it while using different storage or delivery mechanisms. A consumer that accepts the interface depends on the required capability instead of one concrete implementation. This is especially helpful for testing code that normally performs external effects, such as writing a report or reading from a service.

Supply the collaborator to the consumer rather than hiding construction inside the operation. Tests can then provide a predictable implementation and inspect the requested behavior. Keep calculation separate from persistence so the core transformation remains easy to test. An interface does not guarantee correct behavior by itself: document ordering, failures, and side effects, and test implementations against those expectations.

PHP example
<?php
interface Formatter { public function format(int $value): string; }
final class CountFormatter implements Formatter {
    public function format(int $value): string { return "Count: " . $value; }
}
function report(Formatter $formatter, int $value): string {
    return $formatter->format($value);
}
echo report(new CountFormatter(), 6), "
";
Result
Count: 6

The report function requires Formatter behavior. Another compatible implementation can be supplied without changing report’s calculation or call site structure.

Try it yourself

Define a text sink interface and inject it into a function that writes one already-formatted report.

Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.

CHECK YOUR UNDERSTANDING

Chapter checkpoint

What benefit comes from accepting a Formatter interface instead of constructing one concrete formatter inside report?