[英]Can we force concrete classes to implement an interface specified in an abstract class in PHP?
是否可以在抽象類中指定必須由PHP的具體實現來實現的接口?
目前,我們正在做類似以下的事情(希望可以簡單到可以遵循):
<?php
declare(strict_types=1);
interface SensorObserver
{
public function sensorChanged( array $sensorData );
}
class SensorSubject
{
protected $observers = [];
public function addSensorObserver( SensorObserver $sensorObserver ) : bool
{
if ( !in_array( $sensorObserver, $this->observers ) )
{
$this->observers[] = $sensorObserver;
return true;
}
return false;
}
public function removeSensorObserver( SensorObserver $sensorObserver ) : bool
{
if ( !in_array( $sensorObserver, $this->observers ) )
{
return false;
}
else
{
unset( $this->observers[array_search( $sensorObserver, $this->observers )]);
return true;
}
}
public function notifyObservers( array $sensorData )
{
foreach( $this->observers as $observer )
{
$observer->sensorChanged( $sensorData );
}
}
}
abstract class GenericDisplay
{
protected $name;
protected $sensorData;
protected $displayData;
abstract public function showDisplay();
abstract protected function generateDisplayData();
public function __construct( string $name )
{
$this->name = $name;
$this->sensorData = [];
$this->displayData = [];
}
}
class DisplayDeviceA extends GenericDisplay implements SensorObserver
{
public function __construct()
{
parent::__construct( 'DisplayDeviceA' );
$this->sensorData = [ 'SensorTypeA' => 0.0, 'SensorTypeB' => 0.0 ];
$this->generateDisplayData();
}
public function showDisplay()
{
echo PHP_EOL . "{$this->name}: " . PHP_EOL;
foreach ( $this->displayData as $key => $value )
{
echo "{$key}: {$value}" . PHP_EOL;
}
}
protected function generateDisplayData()
{
// Complicated processing done for output here :)
$this->displayData = $this->sensorData;
}
public function sensorChanged( array $sensorData )
{
$dirtySensorData = false;
foreach( $sensorData as $key => $value )
{
if ( array_key_exists( $key, $this->sensorData ) )
{
// This is just an example, <imagine custom processing here when sensor data changes />,
// otherwise we could just implement in the base abstract class or perhaps with a trait
$this->sensorData[$key] = $value;
$dirtySensorData = true;
}
}
if ( $dirtySensorData )
{
$this->generateDisplayData();
}
}
}
class DisplayDeviceB extends GenericDisplay implements SensorObserver
{
public function __construct()
{
parent::__construct( 'DisplayDeviceB' );
$this->sensorData = [ 'SensorTypeA' => 0.0, 'SensorTypeB' => 0.0, 'SensorTypeC' => 0.0 ];
$this->generateDisplayData();
}
public function showDisplay()
{
echo PHP_EOL . "{$this->name}: " . PHP_EOL;
foreach ( $this->displayData as $key => $value )
{
echo "{$key} => {$value}" . PHP_EOL;
}
}
protected function generateDisplayData()
{
// Complicated processing done for output here :)
$this->displayData = $this->sensorData;
}
public function sensorChanged( array $sensorData )
{
$dirtySensorData = false;
foreach( $sensorData as $key => $value )
{
if ( array_key_exists( $key, $this->sensorData ) )
{
// Again, just an example...
$this->sensorData[$key] = $value;
$dirtySensorData = true;
}
}
if ( $dirtySensorData )
{
$this->generateDisplayData();
}
}
}
class DisplayDeviceC extends GenericDisplay implements SensorObserver
{
public function __construct()
{
parent::__construct( 'DisplayDeviceC' );
$this->sensorData = [ 'SensorTypeB' => 0.0, 'SensorTypeD' => 0.0 ];
$this->generateDisplayData();
}
public function showDisplay()
{
echo PHP_EOL . "{$this->name}: " . PHP_EOL;
foreach ( $this->displayData as $key => $value )
{
echo "{$key} --> {$value}" . PHP_EOL;
}
}
protected function generateDisplayData()
{
// Complicated processing done for output here :)
$this->displayData = $this->sensorData;
}
public function sensorChanged( array $sensorData )
{
$dirtySensorData = false;
foreach( $sensorData as $key => $value )
{
if ( array_key_exists( $key, $this->sensorData ) )
{
// Again, just an example...
$this->sensorData[$key] = $value;
$dirtySensorData = true;
}
}
if ( $dirtySensorData )
{
$this->generateDisplayData();
}
}
}
$testDisplays = [ new DisplayDeviceA(), new DisplayDeviceB(), new DisplayDeviceC() ];
foreach( $testDisplays as $display )
{
$display->showDisplay();
}
$sensorSubject = new SensorSubject();
foreach( $testDisplays as $display )
{
$sensorSubject->addSensorObserver( $display );
}
$sensorSubject->notifyObservers( ['SensorTypeB' => 10.0, 'SensorTypeD' => 5.0] );
foreach( $testDisplays as $display )
{
$display->showDisplay();
}
想知道是否有某種寫方法:
interface SensorObserver
{
public function sensorChanged( array $sensorData );
}
abstract class GenericDisplay implements SensorObserver
{
...
abstract public function sensorChanged( array $sensorData );
...
}
class ConcreteDisplay extends GenericDisplay
{
public function sensorChanged( array $sensorData ) { ... };
}
感謝下面的@Mark Baker和@Pael Petrov。 如果有人偶然發現此問題,請使用以下示例:
<?php
interface AnInterface
{
public function foo();
}
abstract class AbstractClass implements AnInterface
{
//...
}
class ConcreteClass extends AbstractClass
{
public function foo()
{
echo 'foo';
}
}
$concrete = new ConcreteClass();
$concrete->foo();
如果抽象類實現了某些接口,則具體類會自動實現抽象類的所有接口,因此您只需要擴展抽象類即可:
class ConcreteDisplay extends GenericDisplay
{
//implement interface methods here
//if not implemented in the parend class
}
這樣就可以了
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.