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.
I think it's important to, first, clarify terminology, in order to more elaborately answer this question.
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.
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.
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
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With