Principles

Interface Segregation Principle

Make fine-grained interfaces that are client-specific.

Uncle Bob introduced this principle when he collaborated with Xerox. They couldn't cope with the ever-lengthening process of implementing changes to their code. The rule is: “No client should be forced to depend on methods it does not use”. The user of the interface should not be forced to rely on methods he does not use. We should not use “fat interfaces” that declare multiple methods if any of them could be left unused. Better to have a few dedicated small interfaces than one that is too general. It is also in line with the single responsibility principle.

So let's look at some badly written code that does not follow the interface segregation principle. I present to you the Exportable, PHP Interface. An interface that allows you to export something to PDF and export something to CSV. We also have an Invoice and a CreditNote class.

interface Exportable
{
    public function getPDF();
    public function getCSV();
}
class Invoice implements Exportable
{
    public function getPDF() {
        // ...
    }
    public function getCSV() {
        // ...
    }
}
class CreditNote implements Exportable
{
    public function getPDF() {
        throw new \NotUsedFeatureException();
    }
    public function getCSV() {
        // ...
    }
}

We can download the Invoice in PDF and CSV. We can download a CSV of the CreditNote. But downloading the CreditNote as a PDF was useless functionality and was never implemented (it throws an exception right now).

We shouldn't force our interface implementations to implement methods they don't use. In the above case, we forced the CreditNote class to do so, it implements the getPDF() method even though it does not need it at all.

So how should it look to be good?

According to the interface segregation principle, we have to separate the interfaces. We divide Exportable and create an interface ExportablePdf and create an interface ExportableCSV.

interface ExportablePdf
{
    public function getPDF();
}
interface ExportableCSV
{
    public function getCSV();
}
class Invoice implements ExportablePdf, ExportableCSV
{
    public function getPDF() {
        //
    }
    public function getCSV() {
        //
    }
}
class CreditNote implements ExportableCSV
{
    public function getCSV() {
        //
    }
}

This way, CreditNote no longer has to worry about implementing an unused getPDF() method. If it is needed in the future, you just implement the separate interface. As you can see here, specific interfaces are better.

The example of ReadOnlyFile related to the Liskov principle is also a good example of the Interface segregation principle. There, the File class has been doing too many things, it's better to have separate interfaces for each action.

That's interface segregation, easy.

Conclusion

The conclusion here is simple, we can end up with a "fat" class with multitudes of methods specific to a variety of different features. A system may become so coupled at multiple levels that it is no longer possible to make a change in one place without necessitating many additional changes.

Copyright © 2026