Конструктор класса PHP в интерфейсе или классе

У меня возникли проблемы с мышлением о хорошей структуре для создания моих классов и объектов. В приведенном ниже коде я использую интерфейс для определения методов класса, но также хочу передать соединение с базой данных с моим конструктором, чтобы класс имел это соединение для работы. Правильно ли это, когда я закодировал его ниже, что конструктор помещен в мой класс и методы в моем интерфейсе?

interface IDataItem
{
    public function saveItem(Item $theItem);
}

class DataItem implements IDataItem{
    public function __construct(Database $database) 
    { 
        $this->database = $database;
    }

    public function saveItem(Item $item) 
    {       
        //save the item
    }
}


$db = new Database(); //from a database class
$dataItem = new DataItem($db);          
$dataItem->saveItem($anItem);   

Ответ 1

Я лично не думаю, что вы должны поместить конструктор в интерфейс, потому что вы никогда не создадите новый объект, вызвав конструктор, не зная о том, какую реализацию вы используете.

В вашем коде есть ошибка, метод в интерфейсе не может иметь реализацию, он должен быть просто объявлением, вроде этого

interface IDataItem
{
    public function saveItem($theItem);
}

Ответ 2

Хотя технически возможно добавить конструктор в интерфейс, интерфейсы не должны определять конструктор, потому что это будет деталь реализации класса реализации. Интерфейс должен просто определить открытый API, к которому могут обратиться другие соавторы. То есть, они не должны обеспечивать выполнение конкретной реализации.

Если вы поместите конструктор с просьбой о подключении к базе данных в интерфейсе, вы должны ограничить конкретные классы зависимостями в сигнатуре конструктора. Если конкретный класс, реализующий интерфейс, нуждается в другом (поскольку он сохраняет в Webservice) или дополнительной (возможно, Logger) зависимости, вы не можете сделать это с вашим интерфейсом.

Ответ 3

Это немного не соответствует теме, но я думаю, что это подчеркивает случай, когда было бы полезно иметь конструктор, определенный в интерфейсе.

Можно создать экземпляр объекта, не зная его класса. Вот простой пример:

interface Animal
{
    public function __construct($name);
    public function speak();
    public function getName();
}

class Cat implements Animal
{
    protected $name=null;
    public function __construct($name){ $this->name=$name; }
    public function speak(){ echo 'meow'; }
    public function getName(){ return $this->name;}
}

class Dog implements Animal
{
    protected $name=null;
    public function __construct($name){ $this->name=$name; }
    public function speak(){ echo 'woof'; }
    public function getName(){ return $this->name;}
}

$animals=Array(array('name'=>'Felix','type'=>'Cat'),array('name'=>'Fido','type'=>'Dog'));

foreach($animals as $a)
{
    $theAnimal=new $a['type']($a['name']);
    echo '<p>speak, '.$theAnimal->getName().'</p><p>';
    $theAnimal->speak();
    echo '</p>';
}

Я использовал что-то вроде этого для маршрутизации URL-адресов, чтобы сопоставлять URL-адреса своим контроллерам верхнего уровня.

Ответ 4

Интерфейсы - это всего лишь контракт на принудительное использование классов, которые могут быть несвязанными, будут реализовывать одни и те же методы.

Поскольку вы должны явно знать класс при его создании, бесполезно помещать конструктор в интерфейс. Вы никогда не вызовете конструктор через интерфейс. Ваше текущее решение верное.

Ответ 5

Сделайте переменную для хранения дескриптора db в вашем классе.