BreadcrumbHomeResourcesBlog What Is An Interface In PHP? May 21, 2020 What Is an Interface In PHP?PHP DevelopmentBy Matthew Weier O’PhinneyPHP interfaces provide reusable types detailing specific behaviors that your application can consume. In particular, they allow you to create classes that have known, expected behaviors that fit within your own application architecture. PHP interfaces also allow you to substitute different implementations, regardless of normal class inheritance, giving you more flexibility in how your structure your applications.In this blog, we dive in on PHP interfaces, including basic concepts and terminology, the role of PHP interfaces in object-oriented programming, and more.Table of ContentsWhat Is a PHP Interface?PHP Interface BasicsInheritance and SubstitutionFive Principles for Object-Oriented ProgrammingWhat Can We Define In an PHP Interface?Ability to Implement Multiple InheritanceNaming PHP InterfacesFinal ThoughtsTable of Contents1 - What Is a PHP Interface?2 - PHP Interface Basics3 - Inheritance and Substitution4 - Five Principles for Object-Oriented Programming5 - What Can We Define In an PHP Interface?6 - Ability to Implement Multiple Inheritance7 - Naming PHP Interfaces8 - Final ThoughtsBack to topWhat Is a PHP Interface?A PHP interface defines a contract which a class must fulfill. If a PHP class is a blueprint for objects, an interface is a blueprint for classes. Any class implementing a given interface can be expected to have the same behavior in terms of what can be called, how it can be called, and what will be returned.Back to topPHP Interface BasicsFor an example of PHP Interface basics, we will consider "something that vocalizes". In the real world, this could be a bird ("tweets"), a dog ("barks"), a cat ("meows"), or a human ("sings"). The details of vocalization are specific to each type, but each can vocalize.We could describe this as follows:interface Vocalizer { public function vocalize(string $message): string; } What we are saying above is: given a string $message, vocalize() will return what is heard as a string.Now, an interface doesn't do anything on its own. It does, however, act as a PHP type. This means you can type hint on it as an argument, or even return something of that type from a function or method.To create something of that type, we need to have an implementation available. Classes can implement an interface:class Bird implements Vocalizer { public function vocalize(string $message): string { return sprintf('<tweet>%s</tweet>', $message); } } Let's say we have a function as follows:function prepareMessage(string $message, Vocalizer $vocalizer): string { return $vocalizer->vocalize($message); } The above function can be called with any $vocalizer that implements Vocalizer:$chickadee = new Bird(); echo prepareMessage('a song', $chickadee); // "<tweet>a song</tweet>"Want to Expand Your PHP Skills?Zend offers a variety of training courses, from basic to advanced. Explore our training options via the link below.Explore Our Training CoursesBack to topInheritance and SubstitutionIn a nutshell, interfaces give us a way to provide features without requiring class inheritance. This can be really useful for adapting existing classes to work in other contexts. As an example, let's say we had a Bird class already that did not implement Vocalizer, but we had essentially equivalent functionality via a method tweet():class Bird { public function tweet(string $message): string { return sprintf('<tweet>%s</tweet>', $message); } } We could do one of two things to make this class a Vocalizer at this point, while keeping all existing functionality.First, we could update the class to directly implement the Vocalizer interface:class Bird implements Vocalizer { public function vocalize(string $message): string { return $this->tweet($message); } public function tweet(string $message): string { return sprintf('<tweet>%s</tweet>', $message); } } Alternately, we could create an extension of Bird that implements Vocalizer:class VocalizingBird extends Bird implements Vocalizer { public function vocalize(string $message): string { return $this->tweet($message); } } Because this latter is an extension of Bird, it fulfills the Bird type for typehints; because it also implements Vocalizer, it also fulfills that type. You could also accomplish the above via an anonymous class implementation:$bird = new class extends Bird implements Vocalizer { public function vocalize(string $message): string { return $this->tweet($message); } }; This leads us to a key rationale for using interfaces: the ability to substitute one type for another. This ability ties directly to one of the five principles of object-oriented programming — the dependency inversion principle.Back to topFive Principles for Object-Oriented ProgrammingWhen performing object-oriented programming, there is a set of five core design principles that are recommended for creating flexible, maintainable architectures known as the SOLID principles:Single-responsibility principleOpen-closed principleLiskov substitution principleInterface segregation principleDependency inversion principleDependency Inversion PrincipleWhile we won't talk about all the principles included in OOP, the dependency inversion principle is directly tied to interfaces.The dependency inversion principle states that we should depend on abstractions, not implementations. What does that mean?If we are only worried about vocalization, we should not need to worry about whether or not we have a Bird, a Human, or an Animal. We should worry about whether or not we have something capable of vocalization. Interfaces allow us to define these capabilities, and then allow our code to typehint against those capabilities, and not a more specific type. This in turn allows us to substitute different types when they fulfill the contract defined by the interface.Common Mistake When Performing Object-Oriented ProgrammingOne common mistake when beginning to perform object-oriented programming is to create a strict inheritance tree: a base class, and then subtypes of that base class, and then implementations of those subtypes, and so on. This can lead to creating a class that technically has a dozen or more different behaviors, but which is only used for one of them. By splitting these behaviors out into different interfaces, we can create classes that implement only specific behaviors, and use them wherever those behaviors are needed.Back to topWhat Can We Define In an PHP Interface?Now that we have a basic idea of what an interface is, why we might use one, and how we can implement one? What exactly can we define in an interface?Interfaces in PHP are limited to: • Publicly visible methods. • Publicly visible constants.In our previous article on PHP classes, we noted that visibility is a more advanced topic. It still is, but we can cover some basics. In a nutshell, visibility helps detail what can use the functionality, and where. Something that has public visibility can be accessed both within class methods, as well as from instances. What is meant by the latter? In the following:$chickadee = new Bird();$chickadee is an instance.Digression: Class ConstantsIn the article on classes we didn't cover class constants. A class constant is just like a normal PHP constant in that it details a value that, well, remains constant. It's a value that cannot be reassigned later. To declare a class constant, you use the const keyword within your class declaration, and optionally a visibility operator (like properties and methods, visibility defaults to public):class Bird { public const TAXONOMY_CLASS = 'aves'; } You then refer to using the class name and constant name, separated by:$taxonomy = Bird::TAXONOMY_CLASS;A class constant can be any scalar type, or an array, as long as no members of the array are objects. They can even refer to other constants if needed.By convention, constant names are usually in ALL UPPERCASE, using underscore separators.Constants defined on an interface are inherited by all implementations.When defining a method on an interface, you omit the body and its braces, and instead end the declaration with a semi-colon (;); you are defining a signature only. These indicate what the implementation must define in order to be valid.We've already seen a method definition previously, when we defined a vocalize() method on our Vocalizer interface:public function vocalize(string $message): string;As such, any implementation must define this method, and be compatible. They can add more arguments — but only if those arguments are optional. That's the only way they can differ.Back to topAbility to Implement Multiple InheritanceOne feature some languages offer is multiple inheritance. This feature allows an object to extend multiple other types, and thus fulfill them all. As an example, a Horse class could extend both an Animal and a Vehicle class.PHP does not offer multiple inheritance, at least not directly. What it does provide, however, is the ability to implement multiple interfaces. This can be useful particularly when you want to describe a subset of features a particular class provides within a given context. Example of Implementing Multiple InterfacesAs an example, the laminas/laminas-cache package defines a variety of interfaces describing storage adapter capabilities, including FlushableInterface, OptimizableInterface, ClearByPrefixInterface, TaggableInterface, etc. Individual adapters are all storage adapters, but they can indicate they have other capabilities by implementing these interfaces.To implement multiple interfaces, you provide a comma-separated list of interfaces following the implements keyword when declaring your class:class MyCustomStorageAdapter extends AbstractAdapter implements ClearByStorageInterface, FlushableInterface, OptimizableInterface, TaggableInterface { // . . . } An instance of this class would then fulfill typehints against each of these interfaces.Back to topNaming PHP InterfacesHow should you name your interface? Generally speaking, name it based on the behaviors it describes. Per our example, we were defining something that vocalizes, so we named the interface Vocalizer.This can be difficult to figure out, particularly if you extract an interface from a class you've previously defined, where the logical name is already the name of an existing class (e.g., you might want to define a Logger interface, but a Logger class already exists). Sometimes the naming difficulty is due to having a team of developers from different backgrounds or countries (e.g., some members of the team might not share the same native language). As such, many projects use an Interface suffix to simplify the naming decision, as well as to call out which class files in a project are contracts versus implementations.You and your team should decide which approach makes most sense for you!Back to topFinal ThoughtsIn this blog, we've talked through the basics of PHP interfaces, the role they play in object-oriented programming, and general best practices teams can employ as they work with PHP interfaces. That said, this write-up is far from exhaustive. Zend by Perforce has a number of resources to help you learn more about principles of object-oriented programming in the PHP language, and emerging concepts that can help your team stay up to speed with PHP.Need Help Modernizing Your PHP?Zend offers a full suite of PHP products and services that can take your PHP applications to the next level -- including PHP LTS, migration services, consultative services, and more. Contact us today to learn more.Contact UsAdditional ResourcesWhite Paper - Writing PHP ExtensionsFree Training Course: Installing PHPFree Training Course: PHP BasicsFree Training Course: Interactive Web FormsBlog - What Is a PHP Class?Blog - Introducing JobQueue for ZendPHPBlog - Using Containers to Improve PHP Application SecurityBlog - PHP Configuration Management and Why It Matters Back to top
Matthew Weier O’Phinney Senior Product Manager, OpenLogic and Zend by Perforce Matthew began developing on Zend Framework (ZF) before its first public release, and led the project for Zend from 2009 through 2019. He is a founding member of the PHP Framework Interop Group (PHP-FIG), which creates and promotes standards for the PHP ecosystem — and is serving his second elected term on the PHP-FIG Core Committee.