Categories


Archives


Recent Posts


Categories


PHP Primer: Interfaces

astorm

Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

No Frills Magento Layout is the only Magento front end book you'll ever need. Get your copy today!

On a “what they do level”, interfaces are pretty simple. Consider the following PHP class

<?php

class Foo extends Bar
{    
}

We’re all (I hope!) familiar with the idea of one class extending another. Interfaces allows a PHP class to do something else. With interfaces, a PHP class may also implement something

<?php

class Foo extends Bar implements BazInterface
{    
}

In the above code sample, the class Foo implements the interface named BazInterface.

As to what it means to implement an interface, consider this simple program

#File: interface-example.php   
<?php

interface AlohaInterface
{
}

class Hello implements AlohaInterface
{
    public function sayHello()
    {
        echo 'Hello',"\n";
    }
}

$cmd = new Hello;            
$cmd->sayHello();

You’ll notice in this program we’ve defined an interface named AlohaInterface (interfaces don’t need the word Interface in their name, it’s just a common convention), and our class Hello implements this interface. If we run this program from the command line or a browser, we’ll see the following output

$ php interface-example.php 
Hello

So far, the interface hasn’t had any measurable impact on our program. However, if we change the interface

#File: interface-example.php  
//... 
interface AlohaInterface
{
    public function sayHello();
    public function sayGoodbye();
}
//...

and try running our program again, we’ll get the following error

PHP Fatal error:  Class Hello contains 1 abstract method and must therefore 
be declared abstract or implement the remaining methods 
(AlohaInterface::sayGoodbye) in 
interface-example.php on line 15

If this is gobbledygook to you, don’t worry, it’s gobbledygook to everyone at first. The key to understanding these sorts of error messages is to understand what an interface is for.

What is an Interface

Think of an interface like a stencil for your class. When you implement an interface, it’s sort of like telling PHP

Hey, I’m making this sort of class, so make sure I actually do the job right

When you define an interface, you’re making the stencil for your class. When you said

#File: interface-example.php  
//... 
interface AlohaInterface
{
    public function sayHello();
    public function sayGoodbye();
}
//...

You were telling PHP that any class that implements the AlohaInterface must define both a sayHello method, and a sayGoodbye method. You’ll notice the methods above don’t have any body. That’s because they’re not real methods, they’re just us telling PHP what a class should look like. Because they’re “not real”, we call these abstract methods.

So, going back to our error message

PHP Fatal error:  Class Hello contains 1 abstract method and must therefore 
be declared abstract or implement the remaining methods 
(AlohaInterface::sayGoodbye) in 
interface-example.php on line 15

PHP was telling us that, because our Class Hello has an interface with an abstract method, that we need to define (the error message uses the word implement) the abstract method (AlohaInterface::sayGoodbye).

So lets define it!

#File: interface-example.php   
//...
class Hello implements AlohaInterface
{
    public function sayHello()
    {
        echo 'Hello',"\n";
    }

    public function sayGoodbye()
    {
        echo 'Goodbye',"\n";
    }
}
//...

Try running the program with the above class definition in place, and everything should be back to normal.

$ php interface-example.php 
Hello

That’s all an interface is — it’s a way to ensure a class has a certain number of methods. As usual, this is a quick primer: The PHP manual has the full story on interfaces, as well as their close cousins, abstract classes.

Why Interfaces

We started this article saying that the “what they do” of interfaces was relatively simple. The “why” of interfaces is a harder story to tell. If you’re coming from shell scripting, or even certain sorts of application development, you’re probably wracking your brain for a reason to use interfaces.

Hint: The reason you’re having so much trouble thinking of a reason is — there isn’t one.

Interfaces only make sense if you’re building programmatic systems for other people to use. They allow a system developer to specify exactly how certain classes need to behave. Magento 1 contained numerous examples of this. Consider the shipping carrier classes

class Mage_Shipping_Model_Carrier_Flatrate
    extends Mage_Shipping_Model_Carrier_Abstract
    implements Mage_Shipping_Model_Carrier_Interface

Whenever you wanted to implement a new shipping carrier in Magento 1, you’d start with a class that implemented the Mage_Shipping_Model_Carrier_Interface. This forced you to define the same methods that the other shipping carrier classes had. This, in turn, meant the Magento systems code for fetching carrier rates could safely assume your carrier object had the same methods as the other carrier objects.

Interfaces are a way for programmers to communicate indirectly. By looking at the interfaces defined in a system, you’ll start to get an idea of what you’ll need to do to customize a system, without needing to talk to the original developer or going through a tutorial.

Java Legacy

Interfaces are another one of those features we get from Java, and that play a slightly different role in a dynamic language like PHP. That said, I think they’re one of the features that makes sense in PHP and can help avoid a certain class of bugs.

Consider the following pseudo-code

function someFunction ($object, $flag)
{
    $object->doTheThing();
    if($flag)
    {
        $object->doTheOtherThing();
    }    
}

In the above code, if $object doesn’t implement a doTheThing method — calling someFunction will always fail. However, if $object does implement doTheThing but doesn’t implement doTheOtherThing, the program might not fail, depending on the value of $flag. This mean it’s possible that a developer will ship this code to production with a lurking bug. You might say tests could catch this, and you’d be right, but I could also say there are large swaths of the industry where tests don’t catch this. This is where interfaces, combined with PHP type hints, can save us

interface SomeInterface
{
    public function doTheThing();
    public function doTheOtherThing();
}

@highlightsyntax@php 
function someFunction (SomeInterface $object, $flag)
{
    $object->doTheThing();
    if($flag)
    {
        $object->doTheOtherThing();
    }    
}       

By using an interface as a type hint, we can ensure no one calls someFunction with an object that doesn’t have all the needed methods.

Regardless of what you think of interfaces and programming by contract, they’re part of the PHP world now. Knowing how to read code that uses interfaces will be a vital skill for anyone working with modern PHP systems.

Originally published July 18, 2015
Series Navigation<< PHP Primer: NamespacesDesign Patterns, PHP, and Magento >>