试图使用最佳实践/设计模式失去对同一财产的访问权限

时间:2010-01-20 22:13:07

标签: php design-patterns

我有:

  • 在实现Validator的类中:
    • $ errormessages property
    • 一个isCorrect()方法

在isCorrect方法中,我有:

switch ($type): 
    case 'email':
        isEmailCorrect();
    case 'password':
        isPasswordCorrect();
    case 'x':
        isXCorrect();

isEmailCorrect(),isPasswordCorrect()和isXCorrect()可以访问包含所有错误消息的同一属性

现在,我有:

    验证员中的
    • $ errormessages property
  • 扩展Validator的EmailValidator类中的
    • 一个isCorrect()方法
  • 扩展Validator的PasswordValidator类中的
    • 一个isCorrect()方法
  • 在扩展Validator的XValidator类中:
    • 一个isCorrect()方法

现在,在调用isCorrect()方法的文件中,我有:

$EmailValidator = new EmailValidator();
$PasswordValidator = new PasswordValidator();
$XValidator = new XValidator();

$EmailValidator->isCorrect()$PasswordValidator->isCorrect()$XValidator->isCorrect()无法访问包含所有错误消息的同一媒体资源

$ errormessages在不同类的不同实例中。他们应该是一个,但是三个。

现在怎么办?

5 个答案:

答案 0 :(得分:2)

我认为你应该开发另一个类:ValidatorChain,它接受任意数量的验证器,并聚合它已经测试过的所有验证器的错误消息

有关参考,请参阅docs on Zend Framework's Validator Chain

修改

现在我重新评估你的问题(感谢Bryan M的评论);为什么您希望每个Validator都能访问其他Validator的错误消息?我会说收集每个Validators的错误消息是层次结构中较高层对象的责任。

但是,如果您希望各个验证器能够根据上下文执行操作,换句话说,根据其他验证器的结果,我想您可以向{{1}添加$ context参数} 方法。例如,这可以接受任意数量的Validators或类似的东西。

类似的东西:

isCorrect

用法:

interface ValidatorInterface
{
    public function isCorrect( array $context );
    public function getMessages();
}

abstract class ValidatorContextOptions
{
    const SHOULD_BE_PRESENT = 'shouldBePresent';
    const SHOULD_NOT_BE_PRESENT = 'shouldNotBePresent';
    const SHOULD_BE_VALID = 'shouldBeValid';
}

class EmailValidator implements ValidatorInterface
{
    protected $_field;

    protected $_contextOptions = array();

    protected $_messages = array();

    public function __construct( $field, array $contextOptions )
    {
        $this->_field = $field;
        $this->_contextOptions = $contextOptions;
    }

    public function isCorrect( array $context = null )
    {
        foreach( $this->_contextOptions as $field => $options )
        {
            foreach( $options as $option )
            {
               switch( $option )
               {
                   case ValidatorContextOptions::SHOULD_NOT_BE_PRESENT:
                       if( isset( $context[ $field ] )
                           && $context[ $field ] instanceof ValidatorInterface )
                       {
                           $this->_messages[] = $field . ' should not be present';
                           return false;
                       }
                       break;
                   case ValidatorContextOptions::SHOULD_BE_PRESENT:
                       if( !isset( $context[ $field ] )
                           || !$context[ $field ] instanceof ValidatorInterface )
                       {
                           $this->_messages[] = $field . ' should be present';
                           return false;
                       }
                       break;
                   case ValidatorContextOptions::SHOULD_BE_VALID:
                       if( !isset( $context[ $field ] )
                           || !$context[ $field ] instanceof ValidatorInterface
                           || !$context[ $field ]->isCorrect() )
                       {
                           $this->_messages[] = $field . ' should be valid';
                           return false;
                       }
                       break;
               }
            }
        }

        // some dummy function which you should replace with real validation
        return isAnEmailAddress( $this->_field );
    }

    public function getMessages()
    {
        return $this->_messages;
    }
}

我在这里展示的,需要更多的思考(而且我真的意味着很多),如同地狱,绝对不是防弹。但是我希望你能抓住我对这个问题的看法。

此外,您在哪里插入需要验证的验证器中的值?

答案 1 :(得分:0)

您可以创建一个外部属性工厂来控制对您的属性的访问,假设您正在讨论属性文件,这是我通常采用的方法。

如果您指的是共享字段,那么您可以将它放在基类中并以这种方式访问​​它。

答案 2 :(得分:0)

我经常使用Zend_Validate类来执行验证,并将任何错误消息聚合到正在验证的对象上的属性(以及控制有效状态的标志)。

我的设置与此类似:

class User {
  public $email;
  protected $_errorMessages = array();

  public function validate()
  {
    $valid = true;

    $emailValidator = new EmailValidator();
    if (!$emailValidator->isCorrect($this->email)) {
      $valid = false;

      // validation message are added to the $errormessages property in
      // the validator class upon failure of isCorrect()
      $this->_errorMessages[] = $emailValidator->getMessages();
    }

    // repeat this for all your validators

    return $valid
  }

  public function getErrorMessages()
  {
     return $this->_errorMessages();
  }
}

// in your page....
if (!$user->validate()) {
  $messages = $user->getErrorMessages();
}

答案 3 :(得分:0)

如果我读了你,你想要多个实例共享相同的错误消息属性,这样你就可以实例化几个验证器,并让它们全部贡献给一个数组。

如果是这种情况,有几种方法可以做到。一种方法是创建一个验证器管理器类,负责实例化和注册验证器。然后,一旦验证完成,您可以调用$validator_manager->getErrors()来汇总在其中注册的所有验证器中出现的错误。

您可以使用的另一种方法是使用单个错误存储类,您可以在每个验证程序的构造函数中获取该类。然后,每个验证器的addError()方法将作业委托给单例。

还有其他方法,但基本上你将不得不使用另一个对象来管理验证器或存储错误。

答案 4 :(得分:0)

下面提到的人使用单身人士。

我不相信这是一种很好的设计模式,特别是因为通常认为单身人士是“反模式”并经常过度/误用。

尽管如此,记住这一点,这是一个例子:

<?php

//Error Class implemented as a Singleton
class ErrorClass
{

  static private $instance = false;
  static private $errorMessages;

  function getInstance() {
    if (!self::$instance) {
      self::$instance = new ErrorClass();
      self::$errorMessages = "No errors;";
    }
    return self::$instance;
  }

  public function setError($errorMessage){
    self::$instance->errorMessages .= $errorMessage;
  }

  public function getError(){
    return self::$instance->errorMessages;
  }

}

abstract class AbstractClass
{

  // Force Extending class to define this method
  abstract protected function isCorrect($b);

  // Common Method for setting error
  public function setError($errorMessage) {
    ErrorClass::getInstance()->setError($errorMessage);   
  }

  // Common Method for getting error
  public function getError() {
    return ErrorClass::getInstance()->getError();   
  }
}

class EmailValidator extends AbstractClass
{

  public function isCorrect($b) {
    if(!$b) {
      $this->setError('EmailValidator->isCorrect();');
    }
  }

}

class PasswordValidator extends AbstractClass
{

  public function isCorrect($b) {
    if(!$b) {
      $this->setError('PasswordValidator->isCorrect();');
    }
  }

}

// Then in your code
$errorState = 1; // used for testing purposes

$EmailValidator = new EmailValidator(); 
$EmailValidator->isCorrect($errorState);

$PasswordValidator = new PasswordValidator(); 
$PasswordValidator->isCorrect($errorState);

echo $EmailValidator->getError();
echo $PasswordValidator->getError();