【问题标题】:Handling Object Dependency处理对象依赖
【发布时间】:2016-02-04 05:54:19
【问题描述】:

考虑下面的类

class User
{
    protected $password;

    public function setPassword($password)
    {
        $this->password = $password;
        return $this;
    }

    public function getPassword()
    {
        return $this->password;
    }
}

我想在用户对象中使用Zend\Crypt\Password\Bcrypt 对密码应用 bcrypt,因为这会创建一个依赖项,我想知道如何正确处理这个问题,我可以考虑几种方法来完成这项工作,让我详细说明

方法 1 :这里我们在方法内实例化类并应用所需的更改。

class User
{
    protected $password;

    public function setPassword($password)
    {
        $bcrypt = new Bcrypt();
        $this->password = $bcrypt->create($password);
        return $this;
    }

    public function getPassword()
    {
        return $this->password;
    }

    public function verifyPassword($password)
    {
        $bcrypt = new Bcrypt();
        return $bcrypt->verify($password, $this->getPassword());
    }
}

据我了解,这不是推荐的方法,因为我在这里看到两个问题

  1. Bcrypt() 被实例化了两次
  2. 这使得 User 对象与 Bcrypt 紧密耦合

我可以通过在类构造函数中实例化一次 Bcrypt() 来解决问题 1,并在需要时使用它,但这并不能解决问题 2

方法2:将Bcrypt对象移出用户类并在设置密码时注入

class User
{
    protected $password;

    public function setPassword($password)
    {
        $this->password = $password;    
        return $this;
    }

    public function getPassword()
    {
        return $this->password;
    }
}

// Init Bcrypt
$bcrypt = new Bcrypt;

// Instantiate user object and create a password
$user = new User;
$user->setPassword($bcrypt->create($password));

// Verify user password
if ($bcrypt->verify($password, $user->getPassword())) {
    // Password is verified
}

最好的方法是什么?

谢谢。

【问题讨论】:

  • 你是对的,我认为更好的方法是有一个 PasswordService 类
  • 如果您打算添加其他处理密码的方法,这种方法是有意义的。否则,使用 Bcrypt 类和 PasswordService 类有什么区别(如果是您的第二个问题)?
  • 除非你使用一些由BcryptProxy 类(目前)实现的HashingMechanism 接口,否则你不会将自己与框架分开。
  • 我正在构建一个 zend-framework-2 模块,它应该可以跨项目重用和扩展,而 Bcrypt 可能对我有用,我不想强​​加给用户,重点是允许开发人员可以根据需要采用它,但默认情况下使用 Bcrypt。

标签: php oop dependency-injection loose-coupling


【解决方案1】:

也许你可以创建一个密码类并将这个逻辑移到那里? 你可以这样做:

class Password
{
    private $password;
    public __construct($password)
    {
        $this->password = $password;
    }

    public crypt(Zend_Crypt_Password_PasswordInterface $crypt)
    {
        $this->password = $crypt->create($password);
    }
}

或使用Decorator。 这两种解决方案都为您提供了扩展代码的可能性。 除了Zend_Crypt_Password_PasswordInterface,您还可以使用自己的Wrapper。恕我直言,这将是更好的解决方案。

然后你可以为特定用户设置密码,它不关心它是否被加密、散列或其他:

class User
{
    private $password;

    public function changePassword(Password $password)
    {
        $this->password = $password;
    }
}

【讨论】:

  • 谢谢,您指出了正确的方向。我最终实现了一个密码接口,所以任何扩展类都必须使用这个接口,这样任何密码创建或匹配算法都可以实现。
【解决方案2】:

我猜第一种方法更好,因为它隐藏在 User 类中使用 bcrypt。

我认为其他程序员在使用User 类时不必记住他必须使用例如$bcrypt->verify

【讨论】:

  • 我认为更好的设计规则总是假设会有变化。虽然我同意隐藏内部函数更好,但同时我也认为有几种创建设计模式可以让我们处理这些事情。
猜你喜欢
  • 1970-01-01
  • 2020-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-15
  • 2022-01-27
  • 2015-11-06
相关资源
最近更新 更多