5

I'm working on a project in PHP. I have several classes that need to implement an interface. Some classes don't need to implement all the methods defined in the interface. Is it possible to only implement some of the methods in a cleaner manner.

Stalin Kay
  • 577
  • 8
  • 18

3 Answers3

5

An interface specifies the methods that must be implemented by a class that implements it, you can't skip some, although you can create additional ones..... what you can do is break your interface into several "smaller" interfaces, and have classes that implement one or more of those as needed, as per example #3 in the PHP Docs

Mark Baker
  • 209,507
  • 32
  • 346
  • 385
  • Thank you @MarkBaker, I guess I've been tunnel-visioned. I wasn't seeing that I could do multiple interface inheritance, probably a case of being a little rusty. – Stalin Kay Nov 24 '15 at 15:59
4

In general an Interface defines which methods your class has to implement. So by definition, forcing the implementation of a method that you don't want to implement renders the concept of an interface invalid.

I see two scenarios:

1. Splitted interfaces

Composing your class interface by using multiple, smaller interfaces gives you a lot of control, but may lead to very small interfaces all over the place.

Example

Consider a request class that may have a json body or some form parameters. Your requests probably will not have both but you still want to provide interfaces to share common class layouts. Using splitted interfaces, you could have

<?php

interface Request {
    public function getHeaders(): array;
}

<?php

interface JsonRequest extends Request {
    public function getJsonBody(): string;
}

<?php

interface FormRequest extends Request {
    public function getFormParameters(): array;
}

and then use this to specify your request class interface:

<?php

class MyRequest implements JsonRequest {
    public function getHeaders(): array
    {
        return ['some' => 'headers'];
    }

    public function getJsonBody(): string
    {
        return json_encode(['some' => 'content']);
    }
}

This approach leaves you with clear and expressive interfaces and also classes that only need to implement what they need. In order to see if a request has a json body, you could check for the interface:

if ($request instanceof JsonRequest) { //...

2. Abstract classes as default provider

A second approach that will allow you to have one common interface and some method that you don't need to implement everywhere is a combination of an interface and an abstract class.

Example

For the same example as above, this approach would give you one interface, one abstract class and then concrete implementations of both. In the example I also set the default to null so that I can have proper checks on the method contents lateron.

The interface:

<?php

interface RequestInterface {
    public function getHeaders(): array;

    public function getJsonBody(): ?string;

    public function getFormParameters(): ?array;
}

The abstract class for making the implementations optional:

<?php

abstract class AbstractRequest implements RequestInterface {
    public function getJsonBody(): ?string
    {
        return null;
    }

    public function getFormParameters(): ?array
    {
        return null;
    }
}

And then the actual request, again this is a json request.

<?php

class MyRequest extends AbstractRequest {
    public function getHeaders(): array
    {
        return ['some' => 'headers'];
    }

    public function getJsonBody(): string
    {
        return json_encode(['some' => 'content']);
    }
}

In order to see if a request has a json body or some form parameters, you could check for null in this example:

if ($request->getJsonBody() !== null) {...

Conclusion

Both ways are technically valid (meaning that both work, not both are good code) and lead to the same class layout with optional methods. Both techniques have upsides and downsides.

Using splitted interfaces provides implicit type safety and makes it easier to rely on the interfaces (also for other downstream decisions, like how to implement parsers or processors by interface, how to handle dependency injection, and so on). The approach is cleaner and results in better code. But it also may lead to having many interfaces for a lot of similar classes with different specialties. Consider having also interfaces for the request methods, some other options, maybe some encodings and so on. If you want to (!), you can end up with many interfaces and little oversight.

Using an abstract class for providing default implementations is working around the idea of interfaces and may result in weakening your code usability. Whenever you find some AbstractRequest somewhere in your application, you may not rely on its interfaces anymore because it may or may not have implemented them. So you'll have to check on all of the methods for which the abstract class provides a default whether or not there is an actual implementation. (Sidenote: otherwise you would have to check for the interfaces, so you'll have to check something anyway) Leaving these downsides aside (and the fact that it's not really the way how things are meant to be implemented) there is the upside, that you'll have one interface with all the method definitions and then one abstract class providing some defaults. Easy to understand - maybe easier than many interfaces in some cases. (Sidenote: Maybe you can even drop the interface completely in the second case, as long as there are no things that can't be declared in the abstract class.)

mvmoay
  • 1,535
  • 3
  • 15
  • 26
0

Interfaces is used in cases when a group of class's have to do the same structure. Than you implement an Interface to enforce that some properties or methods to be implemented.

If have some class, that is not needed to have some interface method, so this class shoud not implement the Interface.

If you have to break rules to implement something, you need to analyze your implementation.

Paulo Teixeira
  • 448
  • 5
  • 11