用PHP组织类

时间:2009-10-05 20:25:24

标签: php oop class organization code-organization

假设我的项目中有以下类:

  
      
  • // 验证类
  •   
  • class 数学 // 数字操纵类
  •   

现在,如果我想验证给定数字的素数,那么插入我的Prime()方法的逻辑位置是什么?我可以想到以下几个选项:

  
      
  • Is_Math ::素()
  •   
  • Math_Is ::素()
  •   

我讨厌这些含糊不清的东西,这会减慢我的思维过程并经常让我误入歧途。还有一些例子:

  
      
  • 是:: Image()或Image :: Is()?
  •   
  • Is_Image :: PNG()或Image_Is :: PNG()?
  •   
  • Is_i18n_US :: ZipCode()或i18n_Is_US :: ZipCode()或   i18n_US_Is :: ZipCode()?
  •   

在Image示例中,第一选择对我来说更有意义,而在i18n示例中,我更喜欢最后一个。没有标准让我觉得整个代码库都很混乱。

组织课程是否有圣杯解决方案?也许是一个不同的范例?

8 个答案:

答案 0 :(得分:10)

对于Math示例,我将实际检查Math类中的数字是否为素数。在Is类中,您将放置一个在需要进行验证时调用的方法。然后,您将从那里使用Math::Prime()

使用Image,这是一种类型检查。除非您确保上传了有效的图像数据,否则您可能不需要为它制作方法。

使用PNG方法,与Math相同。将实际的PNG数据检查器算法放在Image中,并在Is中调用验证器方法。

邮政编码示例应该只在你的Is类中,因为它在字符串原语上运行,可能只使用正则表达式(读取:它不是一个复杂的方法,不像你的PNG检查器可能将是)。

答案 1 :(得分:4)

如果你想尊重SRP(http://en.wikipedia.org/wiki/Single_responsibility_principle),那就去做一点:

选择你的课程并尝试描述它的作用/可以做什么。 如果您的说明中包含“与”,则必须将该方法移至其他类。

见第36页:http://misko.hevery.com/attachments/Guide-Writing%20Testable%20Code.pdf

其他法律(还有更多)将帮助您组织课程:得墨忒耳法律(http://en.wikipedia.org/wiki/Law_of_Demeter)。

为了学到很多并帮助你做出正确的选择,我建议你Misko的博客(谷歌传教士):http://misko.hevery.com

希望这有帮助。

答案 2 :(得分:3)

处理验证本身的所有内容都适合您的Is - 类:

  • 它通过了吗?
  • 哪些部分没有通过?
  • 是否应该在某处记录验证错误?
Zend Framework中的

Zend_Validate提供了这样一种方法,也许你可以从中获得一些灵感。由于这种方法可以让您在所有验证类中实现相同的接口,因此您可以轻松地

  • 使用相同的语法进行验证,与验证哪些数据无关
  • 通过检查名为Is_PrimeIs_Image的所有类,而不是在整个地方检查Math_IsImage_Is,轻松识别您可用的验证规则。

修改
为什么不使用这样的语法:

class Math {
    public function isPrime() {
        $validation_rule = new Is_Prime();
        return (bool) $validation_rule->validates($this->getValue());
    }
}

从而也允许

class Problem {
    public function solveProblem(Math $math) {
        $validation_rule = new Is_Prime();
        if($validation_rule->validates($math->getValue())) {
            return $this->handlePrime($math);
        } else {
            return $this->handleNonPrime($math);
        }
    }
}

答案 3 :(得分:3)

我认为它根本不含糊。 “是”应该是每个例子中的第一个,我会告诉你原因:“是”是验证操作的超集,其中Is :: Math是其成员。

在Is :: Math的情况下,你在做什么?你在做数学运算吗?或者您正在验证数学实体?后者,显然,否则它只是“数学”。

这两项行动中哪一项的范围更广?是什么?还是数学?很明显,因为Is在概念上适用于许多非数学实体,而数学是数学特定的。 (同样在Math :: Factor的情况下,它不会是Factor :: Math,因为Math是Factor所属的超集。)

这种OOPing的全部目的是以有意义的方式对事物进行分组。验证函数,即使它们适用于截然不同类型的实体(素数与PNG图像),它们之间的相似性也比它们所比较的事物更相似。它们将返回相同类型的数据,它们在相同的情况下被调用。

答案 4 :(得分:1)

我认为你所说的问题没有“正确答案”。有些人会把Prime放在Is中,有些人会放在Math中。有歧义。否则你不会问这个问题。

现在,你必须以某种方式解决歧义。你可以考虑一些规则和约定,即哪个类/方法去哪里。但这可能是脆弱的,因为规则并不总是很明显,而且它们可能会变得非常复杂,并且在那时它们不再有用。

我建议您设计这些类,以便通过查看某些方法应该去的名称来显而易见。

不要将您的验证包命名为。它是如此通用的名称,几乎一切都在那里。 IsFile,IsImage,IsLocked,IsAvailable,IsFull - 听起来不太好,好吗?该设计没有凝聚力

最好让验证组件在子系统边界(必须强制执行安全和业务规则)过滤数据,而不是其他任何内容。

做出决定后,你的榜样变得明显。 Prime属于数学。是::图像可能太笼统了。我更喜欢Image :: IsValid,因为你可能还有其他方法在图像上运行(更多的凝聚力)。 否则正如我在开头所说的那样,“Is”会成为所有内容的包包

答案 5 :(得分:1)

我认为“is”根本不属于类名。我认为这是方法。

abstract class Validator {}

class Math_Validator extends Validator
{
  public static function isPrime( $number )
  {
    // whatever
  }
}

class I18N_US_Validator extends Validator
{
  public static function isZipCode( $input )
  {
    // whatever
  }
}

class Image_Validator extends Validator
{
  public static function isPng( $path )
  {
    // whatever
  }
}

Math_Validator::isPrime( 1 );
I18N_US_Validator::isZipCode( '90210' );
Image_Validator::isPng( '/path/to/image.png' );

答案 6 :(得分:0)

  

组织课程是否有圣杯解决方案?也许是一个不同的范例?

不,这是基于类的oop的基本缺陷。这是主观的。

函数式编程(不要与过程式编程混淆)这个问题的问题较少,主要是因为主要构建块要小得多。无类别的oop也更好,是oop和各种函数式编程的混合。

答案 7 :(得分:0)

类可以被认为是做事物的花哨类型,比如验证自己。

abstract class ValidatingType 
{
  protected $val;
  public function __construct($val)
  {
     if(!self::isValid($val))
     {  // complain, perhaps by throwing exception
        throw new Exception("No, you can't do that!");
     }
     $this->val = $val;

  }
  abstract static protected function isValid($val);
}

我们扩展ValidatingType以创建验证类型。这迫使我们创建一个isValid方法。

class ValidatingNumber extends ValidatingType
{
   ...
   static protected function isValid($val)
   {
      return is_numeric($val);
   }
}

class ValidatingPrimeNumber extends ValidatingNumber
{
   /*
    * If your PHP doesn't have late-binding statics, then don't make the abstract 
    * or overridden methods isValid() static.
    */
   static protected function isValid($val)
   {
      return parent::isValid($val) 
             or self::isPrime($val); // defined separately
   }
}

class ValidatingImage extends ValidatingType
{
   ...
   static protected function isValid($val)
   {
      // figure it out, return boolean
   }
}

这种方法的一个优点是你可以继续创建新的验证类型,而且你不会得到一个膨胀的Is类。

这种方法有更多优雅的变化。这是一个简单的变化。语法可能需要清理。