简体   繁体   English

我们是否可以强制具体的类来实现PHP抽象类中指定的接口?

[英]Can we force concrete classes to implement an interface specified in an abstract class in PHP?

Is it possible to specify an interface in an abstract class that must be implemented by concrete implementations in PHP? 是否可以在抽象类中指定必须由PHP的具体实现来实现的接口?

At the moment we are doing something like the following (hopefully made simple enough to follow): 目前,我们正在做类似以下的事情(希望可以简单到可以遵循):

<?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();
}

Wondering if there is essentially some way to write: 想知道是否有某种写方法:

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 ) { ... };
}

Thanks to @Mark Baker and @Pael Petrov below. 感谢下面的@Mark Ba​​ker和@Pael Petrov。 If anybody stumbles across this, a working example: 如果有人偶然发现此问题,请使用以下示例:

<?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();

If an abstract class implements some interface concrete classes automatically implement all the interfaces of the abstract class so you just need to extend the abstract class: 如果抽象类实现了某些接口,则具体类会自动实现抽象类的所有接口,因此您只需要扩展抽象类即可:

class ConcreteDisplay extends GenericDisplay
{
    //implement interface methods here 
    //if not implemented in the parend class
}

This will do the job 这样就可以了

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM