Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are abstract classes necessary in PHP?

We can use simple inheritance or interface instead of abstraction. Why do we need to use abstraction in PHP? and How can we hide basic features using abstraction? I am confused using abstraction and interface and inheritance. Where to use which? Please help to understand me.

like image 519
Rahul Mankar Avatar asked Aug 27 '16 18:08

Rahul Mankar


3 Answers

I think it's important to, first, clarify terminology, in order to more elaborately answer this question.

  1. inheritance
    • Inheritance is actually broadly applied to a lot of Object-Oriented programming principles and concepts. It just entails one thing bred from another. So whether you are implementing an interface or extending a class you are still using a form of inheritance. They aren't mutually exclusive concepts.
  2. interface
    • Try to think of an interface like you would a contract. The contract itself is just a document, usually between two or more parties, that lays out the rules of their relationship. Interfaces, specifically in the context of OOP and PHP, do not provide implementation. They only provide the required public methods that an implementing class MUST implement. Interfaces also cannot be instantiated on their own.
  3. abstract class
    • The abstract class is similar to an interface in that it cannot be instantiated on its own, but does not necessarily enforce a contract on the extending class. Since it's an actual class, and not just an interface, it also allows for implementation. This implementation can be supplied by the abstract class itself, or left up to the extending class, if the method is declared as abstract in the abstract class. It also allows for the implementation of properties and private/protected methods, because the inheritance here acts like a base class and not just a requirement.

So to answer the question, "why do we have abstract classes in PHP", because it's useful. You may see these as intractable ideas at first, but they actually can work together to provide conjoined utility.

Example

Consider that some times an interface isn't enough to create a useful implementation. The interface can only enforce that a method exists and that its signature is compatible with the implemented interface. There may be cases when you wish to provide default implementations of an interface, for example.

interface Device {
    public function input(Stream $in);
    public function output(): Stream;
}

abstract class DefaultDevice implements Device {
    protected $buffer = "";
    public function input(Stream $in) {
        $this->buffer .= $in->read(1024);
        $this->process();
    }
    abstract protected function process();
}

So now any class that extends DefaultDevice can either choose to override the implementation of the input method or not. It also has to implement a process method even though the interface does not require it. This means other classes implementing the Device interface can be backwards compatible and this remains an implementation detail.

Further Example

Separating implementation from specification is generally a key attribute of well-written software.

Take a look at the Device interface itself, as a good example. We rely on the input method to accept a Stream type and the output method to return a Stream type. Since Stream, itself, can actually be an interface this means that any type implementing Stream is acceptable. So I could create my own class and implement the Stream interface without ever breaking this code.

class CustomStream implements Stream {
    public function read($bytes = 1024) {
        /* implementation */
    }
    public function write($data) {
        /* implementation */
    }
}

$device->input(new CustomStream); // this will not throw an error
like image 89
Sherif Avatar answered Nov 14 '22 01:11

Sherif


an abstract class is used to provide a set of data members or methods to be made available to classes which inherit from it, even though the base class is not particularly useful (and should never be instantiated on its own) without an inherited implementation.

from here, inheritance takes over.

an interface on the other hand is to provide a set of rules for implementation that require each class that uses the interface to implement the specifications found therein. classes implementing the same interface do not need to inherit from each other, they implement the interface so they can be used in any application requiring that set of functionality.

like image 28
derelict Avatar answered Nov 14 '22 01:11

derelict


Just as an exercise lets try to create some classes to handle geometric shapes.

The base class:

class Shape
{
    public function draw()
    {
    }
}

Only the relevant part of the base class is described in the code fragment above. Of course, it should have properties to store its position, line color etc and methods (constructor, at least).

A couple of derived classes:

class Circle extends Shape 
{
    public function draw()
    {
        // the code to draw a circle
    }
}

class Rectangle extends Shape
{
    public function draw()
    {
        // the code to draw a rectangle
    }
}

Can we provide an implementation for method draw() in the base class Shape?

Of course not. Shape is generic, it doesn't mean only "circle" or "rectangle" or "triangle". There is no way to provide a reasonable implementation for Shape::draw() because we don't even know what shape it represents.

Is it ok to provide an empty implementation for Shape::draw()?

Apparently it is. However, on a second thought, it's clear that this is not safe. The objects of a class that extends Shape and doesn't provide its own implementation for method draw() cannot be drawn.

Because the class Shape is not able to provide a decent implementation for method shape, it should signal this thing somehow to the derived classes and force them to provide an implementation.

The way it signals this situation is the abstract keyword. An abstract method tells the readers of the class that the class is not able to provide an implementation because it is too generic and it delegates this responsibility to each class that extends it.

A class that has an abstract method is not completely defined. This is the reason why it is an abstract class and it cannot be instantiated.

like image 2
axiac Avatar answered Nov 14 '22 00:11

axiac