Я никогда не использовал интерфейсы или абстрактные классы в PHP, но дошел до того, что я хочу поддерживать похожие, но разные типы одного и того же объекта (в данном случае сетевые коммутаторы) и, возможно, добавить больше в будущем. Я общаюсь с ними через SSH (PHPSecLib), и взаимодействие которых отличается, фактические методы будут одинаковыми.
В моем конкретном случае я считаю, что абстрактный класс, реализующий константы, частные переменные, функции соединения и конструктор / деструкторы, был бы уместен, оставляя расширенные классы ТОЛЬКО для реализации функциональности, где интерфейс был бы просто шаблоном, но каждый расширенный класс мог бы все еще повторно реализуйте методы, которые одинаковы между ними.
Правильно ли я считаю, что абстрактные классы — это путь в этом сценарии? Нужно ли размещать пустые методы в абстрактных классах, которые переопределяются расширенными классами, или у расширенного класса могут быть методы, которых нет в абстрактном классе?
Пример:
<?php
set_include_path(get_include_path() . PATH_SEPARATOR . '/home/devicepo/public_html/include/PHPSecLib');
include('Net/SSH2.php');
include('File/ANSI.php');
abstract class Switch
{
const STATUS_UNKNOWN = "-1";
const STATUS_OFFLINE = "0";
const STATUS_ONLINE = "1";
public $conn;
private $_server;
private $_username;
private $_password;
private $_bashshell;
public function __construct($server, $username, $password)
{
if (!$server)
die("Switch configuration not Defined");
$this->_server = $server;
$this->_username = $username;
$this->_password = $password;
}
public function connect()
{
// Establish new SSH2 Connection
$this->conn = new Net_SSH2($this->_server, 22);
if(!$this->conn->login($this->_username, $this->_password))
{
die("Failed to connect to Switch: " . $this->_server);
}
}
public function enable_port($port)
{
// Define in extended classes
}
public function disable_port($port)
{
// Define in extended classes
}
}
?>
Я считаю, что в вашем случае класс Abstract — это путь. Причины таковы:
Ваши дочерние классы делят большую часть кода с родительским классом
У ваших детских классов есть понятие сходства.
Чтобы быть более конкретным в отношении пункта 2, имейте в виду, что два класса, реализующие один и тот же интерфейс, не обязательно связаны между собой. Интерфейс представляет способность. Рассмотрим, например, самолет и птицу. Оба могут реализовывать плавающий интерфейс, но кроме этого они никак не связаны между собой. С другой стороны, ваши дочерние классы имеют похожий тип. Все они выключатели. Таким образом, ваш абстрактный класс может быть
abstract class BasicSwitch { // You cannot use the name switch
const STATUS_UNKNOWN = "-1";
const STATUS_OFFLINE = "0";
const STATUS_ONLINE = "1";
public $conn;
private $_server;
private $_username;
private $_password;
private $_bashshell;
public function __construct($server, $username, $password) {
if (!$server) die("Switch configuration not Defined");
$this->_server = $server;
$this->_username = $username;
$this->_password = $password;
}
public function connect() {
// Establish new SSH2 Connection
$this->conn = new Net_SSH2($this->_server, 22);
if(!$this->conn->login($this->_username, $this->_password)) {
die("Failed to connect to Switch: " . $this->_server);
}
}
abstract public function enable_port($port);
abstract public function disable_port($port);
}
и конкретная реализация может быть
class CiscoSwitch extends BasicSwitch {
public function __construct($server, $username, $password) {
parent::__construct($server, $username, $password);
}
public function enable_port($port) {
echo 'Port is enabled';
}
public function disable_port($port) {
echo 'Port is disabled';
}
}
Здесь важно помнить, что CiscoSwitch также является разновидностью BasicSwitch. Это означает, что CiscoSwitch можно использовать везде, где ожидается BasicSwitch. Так что учтите, что у вас есть стойка со многими коммутаторами, и вы хотите включить один и тот же порт для всех коммутаторов в стойке. Вот ваш класс Rack:
class Rack {
protected $switches;
public function addSwitch(BasicSwitch $switch) {
$this->switches[] = $switch;
}
public function enable_ports($port) {
foreach($this->switches as $switch) {
$switch->enable_port($port);
}
}
}
Если вы введете подсказку в классе Abstract (BasicSwitch), а не в реализации, вы можете быть уверены, что любой коммутатор в стойке может включать и отключать его порты. Тебе действительно все равно, какой это переключатель. Вы просто знаете, что он может сделать эту работу.
В этом весь код интерфейса, а не реализации. Таким образом, ваш код открыт для расширения, но закрыт для модификации. Вы можете создать столько типов коммутаторов, сколько захотите, но вы будете уверены, что класс Rack продолжит работать.
Других решений пока нет …