简体   繁体   English

PHP:在这种情况下,如何使用扩展接口而不违反SOLID原则?

[英]PHP: How to use extended interfaces without violating SOLID principles in this case?

I'm very sorry for the cryptic title, but I honestly have no idea how to describe it in a short, title-style fashion. 对于隐晦的标题,我感到非常抱歉,但老实说,我不知道如何以简短的标题风格来形容它。

First short version. 第一个简短版本。 Simple email confirmation mechanism. 简单的电子邮件确认机制。 One method is sending email with confirmation link. 一种方法是发送带有确认链接的电子邮件。 After clicking the link, another controller invokes second method, which verifies token from the URL. 单击链接后,另一个控制器调用第二种方法,该方法从URL验证令牌。 Between both actions ConfirmationObject is being stored, with the token and possible other data. 在这两个动作之间,将存储ConfirmationObject以及令牌和其他可能的数据。 After successful confirmation "successHandler" is being used. 成功确认后,将使用“ successHandler”。

Simplified code: 简化代码:

interface SuccessHandlerInterface {
    public function success(ConfirmationObjectInterface $object);
}

class EmailTester {
    public function try(ConfirmationObjectInterface $object) {
        // some code
    }

    public function confirm($token) {
        $confirmationObject = $this->repository->findByToken($token);

        $type = $confirmationObject->getType();
        $successHandler = $this->handlersRegistry->getSuccessHandler($type);
        $successHandler->success($confirmationObject);
    }
}

Now we are going to use it this way: 现在我们将以这种方式使用它:

// Firstly let's implement our own success handler.
class UserRegistrationSuccessHandler implements SuccessHandlerInterface {
    public function success(ConfirmationObjectInterface $object) {
        // Do some stuff on success.
    }
}

// Then let's register this success handler to be available in our `handlersRegistry` object.
$handlersRegistry->addType('user_registration', new UserRegistrationSuccessHandler());

// Now we will extend ConfirmationObjectInterface
interface RegistrationConfirmationObjectInterface extends ConfirmationObjectInterface {
    public function getSomeDataGivenOnRegistration();
}

// And at the end, let's try our email

$confirmationObject = new RegistrationConfirmationObject(); // Which implements above interface.
// $confirmationObject->getType() === 'user_registration'

$emailTester->try($confirmationObject);

// Now confirmation link with token is being sent to the given email. If user will click it, below method will be invoked.
$emailTester->confirm($token);

The problem now is that I would rather like to have RegistrationConfirmationObjectInterface in the success handler available, rather than ConfirmationObjectInterface . 现在的问题是,我希望在成功处理程序中提供RegistrationConfirmationObjectInterface ,而不是ConfirmationObjectInterface

I know I can do: 我知道我可以做:

// Firstly let's implement our own success handler.
class SuccessHandler implements SuccessHandlerInterface {
    public function success(ConfirmationObjectInterface $object) {
        if ($object instanceof RegistrationConfirmationObjectInterface) {
            // Do stuff
        }
    }
}

But it feels bad. 但这感觉不好。 This check is pointless as $object will always be an instance of RegistrationConfirmationObjectInterface . 该检查毫无意义,因为$object始终是RegistrationConfirmationObjectInterface的实例。 How is this design flawed, and how it could be improved? 这种设计有何缺陷,以及如何加以改进?

It is unclear to me why the Confirmation Objects should implement two interfaces. 我不清楚为什么确认对象应实现两个接口。 From what I see here, RegistrationConfirmationObjectInterface only has one method that returns some data structure, and ConfirmationObjectInterface has no methods at all. 从我这里看到的情况来看, RegistrationConfirmationObjectInterface只有一种方法可以返回某些数据结构,而ConfirmationObjectInterface根本没有任何方法。 Is strict type safety really necessary here, especially if you're certain that your custom SuccessHandler will receive RegistrationConfirmationObjectInterface at all times? 在这里真的有严格的类型安全性吗,特别是如果您确定自定义的SuccessHandlerSuccessHandler接收RegistrationConfirmationObjectInterface时?

If ConfirmationObjectInterface implementations contain no logic and are just data structures, replace them with associative arrays. 如果ConfirmationObjectInterface实现不包含任何逻辑,而仅仅是数据结构,则将其替换为关联数组。 Otherwise, I would suggest something like this: 否则,我建议这样的事情:

interface ConfirmationObjectInterface
{
    /**
     * @return array
     */
    public function getData();
}

class RegistrationConfirmationObject implements ConfirmationObjectInterface
{
    public function getData()
    {
        return ['data specific to registration here'];
    }
}

class SomethingElseConfirmationObject implements ConfirmationObjectInterface
{
    public function getData()
    {
        return ['data specific to something else'];
    }
}

Since custom handlers are specific to concrete types, they will know what data to expect from getData() anyway. 由于自定义处理程序是特定于具体类型的,因此他们无论如何都会知道期望从getData()获得哪些数据。

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

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