View Single Post
Old 11-13-2007, 03:15 PM   #1 (permalink)
Karl
The Reckoner
Advanced Programmer Top Contributor 
 
Karl's Avatar
 
Join Date: Sep 2007
Posts: 438
Thanks: 22
Karl is on a distinguished road
Default Working with Interfaces

When you create an interface, you're basically creating a prototype/blueprint of functions that classes using the interface must implement in order to be valid. It's usually easier to learn from example, so here's a basic interface that represents a Page.

PHP Code:
interface PageInterface
{
    public function 
render();

PageInterface specifies that any classes which implement this interface must also implement a public render() function. It's important to note that you must implement the functions with the same visibility (or weaker) - by visibility I am referering to public/private/protected. In this example, any classes implementing PageInterface must also implement render as a public function containing no arguments.

Here are two classes that implement PageInterface. Notice how both classes contain the public render function (without arguments), if you fail to declare this function PHP will throw a fatal error.

PHP Code:
class Login implements PageInterface
{
    public function 
render()
    {
        return 
'Render Login Page';        
    }
}

class 
Register implements PageInterface
{
    public function 
render()
    {
        return 
'Render Register Page';
    }

So what exactly are interfaces for? In the above example I used them to tie together conceptually similar classes. That is, classes that represent something similar. The above classes, Login and Register, represent a Page, this is the concept that ties the classes together. In other words, they provide an interface (prototype) for building classes of similar concepts.

As we've defined both Register and Login as types of PageInterface we can treat them as the same (as types of Page, anyway). Let's say, for some reason you wanted to create collections of pages and render them together -- you probably wouldn't, but it provides a good base for this example -- then you can use the PageInterface to ensure that this collection of Pages all follow the same interface. Since they all follow this interface, they will all implement the render() function.

PHP Code:
class PageCollection
{
    private 
$pPage = array();
    
    public function 
add(PageInterface $pPage)
    {
        
$this->m_aPageCollection[] = $pPage;
    }
    
    public function 
renderPages()
    {
        foreach (
$this->m_aPageCollection as $pPage)
        {
            echo 
$pPage->render();
        }
    }

In the previous class we've used type-hinting to limit the add methods argument $pPage to a class that implements PageInterface. This will stop the user from passing in an instance of a class that doesn't implement this interface.

Inside the renderPages() method, when we're looping through the collection of pages, we can happily call $pPage->render() because we prohibited the add method from adding anything that doesn't implement PageInterface, and since PageInterface specifies the render() method, we know that $pPage must also have a render() method.

This is a good example of polymorphism: When we call render() we know that it will render a page, but we don't know what sort of page we're rendering. Thus, the render() function has many forms (polymorhpism, means many-forms), because it can render a Login page, Register page, or any other "form" of page.

Here's an example of how the class can be used to create and render a collection of pages.:

PHP Code:
$pPageCollection = new PageCollection();
$pPageCollection->add(new Login());
$pPageCollection->add(new Register());
$pPageCollection->renderPages(); 
Trying to add an invalid class would cause a fatal error, thanks to type-hinting and the use of interfaces.

PHP Code:
$pPageCollection = new PageCollection();
$pPageCollection->add(new Login());
$pPageCollection->add(new Register());

// Try to add a DateTime object, this will cause a fatal error
$pPageCollection->add(new DateTime());

$pPageCollection->renderPages(); 
One other major benefit of using interfaces is that unlike subclassing, you're not limited to single inheritance, you can implement mulitple interfaces for a single class. For example, we could create an admin page interface that could specify all pages implementing the interfaces must contain an auth() method. We could then combine this with the PageInterface to create a class that implements two interfaces:

PHP Code:
interface AdminPageInterface
{
    public function 
auth();
}

class 
AdminNews implements PageInterfaceAdminPageInterface
{
    public function 
auth()
    {
        echo 
"Auth Code";
    }
    
    public function 
render()
    {
        echo 
"Render Code";
    }

Obviously the previous example is functionally useless, it does, however, outline the process of implementing multiple interfaces. I think I'll end the article here, and wrap up by saying that interfaces provide a method to specify a prototype for building classes - from another point of view, they allow you to tie together classes that share a similar concept (the interface).
__________________
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
Karl is offline  
Reply With Quote