Question

When defining the structure and inheriting Interface and/or Abstract Class, which one is the best practice? And why? Here are 2 examples:

Here is the example for [Interface] -> [Abstract Class] -> [Class]

Interface DataInterface
{
    public function __construct($connection);
    public function connected();
    public function get();
}

Abstract class BaseData implements DataInterface
{
    protected $connection;

    public function __construct($connection)
    {
        $this->connection = $connection;
    }
}


class UserData extends BaseData
{
    public function exists()
    {
        return is_connected($this->connection);
    }

    public function get()
    {
        return get_data($this->connection);
    }
}

$oUserData = new UserData(new Connection());

And here is the sample for [Abstract Class] -> [Class] without the Interface

Abstract class BaseData
{
    protected $connection;

    public function __construct($connection)
    {
        $this->connection = $connection;
    }

    abstract public function connected();
    abstract public function get();
}

class UserData extends BaseData
{
    public function exists()
    {
        return is_connected($this->connection);
    }

    public function get()
    {
        return get_data($this->connection);
    }
}

$oUserData = new UserData(new Connection());

I am currently creating a small app (might grow larger) and confused on how to implement in the beginning correctly.

By the way, is this declaration for __construct() with parameter make sense in Interface?

public function __construct($connection);
Was it helpful?

Solution

Abstract classes defines an interface that must be implemented to the heirs of the abstract class. An Interface-Construct defines an interface that must be implemented by a class that implements the interface-construct, the implementation of the interface is not limited to a single interface, whereas class inheritance is coupled to a single (abstract) class.

Interfaces in PHP are intentionally used to allow typehints of an limited subset of an entire class interface. There is no reason for an interface on abstract classes aslong their receiver of instances of their heirs did not use them ( with typehinting or logical identification over instanceof / is_a ). The more valuable benefit of interface-constructs are the possibility of replacing an common implementation of an interfaces with a alternate implementation.

In case of your BaseData-Example, i recommend to drop the abstract idea and use a trait and seperate interfaces instead.

trait connectionBrokerConstructor {
    protected $connection;

    public function isConnected()
    {
        return $this->connection instanceof Connection;
    }

    public function setConnection(Connection $connection)
    {
        $this->connection = $connection;
    }
}

interface connectable
{
    public function setConnection(Connection $connection);
    public function isConnected();
}

interface userDataRepositoryInterface
{
    public function get();
}

class UserData implements connectable, userDataRepositoryInterface
{
    use connectionBrokerConstructor;

    public function __construct(Connection $connect = null)
    {
        $this->setConnection($connection);
    }

    public function get()
    {
        return array('something');
    }
}

OTHER TIPS

Really abstract classes and interfaces are different.

Consider an interface as a contract, it lays out the rules that other classes (which implement it) must follow.

Abstract classes on the other hand are more like starting points, which other classes can build on, hence why they are sometimes called base classes.

------- Edit with example

I'm not an expert on such things, but I've always just done interface -> class.

For example, here is a simple interface:

interface AnimalInterface {

  public function all();

  public function findBySlug($slug);

}

And here is the class which implements that interface (simplified):

class AnimalEloquentRepository implements AnimalInterface {

  public function all()
  {
    return Animal::all();
  }

  public function findBySlug($slug)
  {
    return Animal::whereSlug($slug)->first();
  }

}

I do often have a base class, which others extend, but I've only once used an abstract class in a real world app, and that ended up getting replaced.

I'm sure there are better ways to do things, but this has worked really well for me in the past.

My reputation doesn't allow comments, but this statement in tr0y's answer is misleading:

"Abstract classes defines an interface that must be implemented to the heirs of the abstract class."

One of the main differences between an interface and an abstract class is that you are not required to implement any of the methods of an abstract class in a class that extends it. It's quite common for the abstract class to have methods with default behavior and only provide those methods in the heirs if the default behavior is not what you want.

On the other hand, you are require to create all methods specified in an interface in any class that implements that interface.

Another difference is that methods in an interface cannot have a body, while methods in an abstract class must have a body.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top