验证构造函数参数,确保参数具有正确的类型

时间:2011-01-05 14:06:20

标签: php oop validation

编写我的第一个PHP类并遇到了一个问题,以下是我的__construct方法:

public function __construct($foo,$bar) {
       $this->foo = $foo;
       $this->bar = $bar;
}

$foo$bar都是必需的,如果没有它们,方法将无效。当对象被实例化时没有定义它们就可以了:

$var = new Class();

因为这会引发异常(例如,Class需要2个参数,没有设置)。但如果它们被设置但不是正确的类型,那么:

$var = new Class('33','ddd');

由于变量的类型错误,我的方法会失败。

我应该在哪里验证这些?在构造函数中还是在每个方法中?

我现在使用的解决方案现在有效,但我不确定它是否正确:

// $foo needs to be a string with letters only
// $bar needs to be an integer
public function __construct($foo,$bar) {
       $this->foo = $foo;
       $this->bar = $bar;
       if(!is_numeric($bar)){
           // Throw exception
       }
       elseif(other validation case)
       etc...
}

OO编程的概念对我来说是一个新手,所以非常感谢您对任何参考资料的链接。

8 个答案:

答案 0 :(得分:18)

我可能会做这样的事情来防止ctor内部的混乱,并允许类在内部设置它们的值:

class MyClass …

    protected $_foo;

    /**
     * @param  String   $foo    String with letters only
     * @param  Integer  $bar    Any Integer
     * @return void
     * @throws InvalidArgumentException when $foo is not letters only
     * @throws InvalidArgumentException when $bar is not an Integer
     */
    public function __construct($foo, $bar) 
    {
        $this->_setFoo($foo);
        $this->_setBar($bar)
    }

    /**
     * @param  String   $foo    String with letters only
     * @return void
     * @throws InvalidArgumentException when String is not letters only
     */
    protected function _setFoo($foo)
    {
        if (FALSE === $this->_consistsOfLettersOnly($foo)) {
            throw new InvalidArgumentException(
                '$foo should consists of letters only'
            );
        }
        $this->_foo = $foo;
    }  

    …

这具有额外的优势,如果您以后需要公开公开setter,则只需更改visibility关键字。

对它自己的方法进行验证并不是绝对必要的,但我认为它使代码更具可读性。如果您发现该类中的另一个属性需要相同的验证,您也可以更轻松地重复使用它。

答案 1 :(得分:2)

验证构造函数中的类型(根据你的例子)对我来说似乎是合乎逻辑的选择,尽管如果参数是可选的,它有点奇怪。如果是这种情况,你应该设置安全默认值...

public function __construct($foo=null, $bar=null)

也就是说,您可以在PHP中使用type hinting作为参数,但我相信这只适用于数组和类。 (这并不奇怪,因为在PHP中没有整数或字符串类型。)

正如其他人所说的,你还应该确保你在任何你所拥有的setter中进行验证,或者(更好的是)只需在构造函数中调用setter,以确保没有重复的代码。

答案 2 :(得分:0)

如果需要$ foo和$ bar,那么在__construct中验证它们是最好的选择(如果不是:使用setter并在那里验证)。如果你在每种方法中都这样做,你最终会得到重复的代码。想象一下,如果数据类型发生变化,您必须更改每个方法......

如果您非常挑剔,可以在将$ bar分配给$ this->栏之前致电is_numeric,因为如果检查数值失败则不需要分配。

答案 3 :(得分:0)

最好的方法是使用getter和setter - 例如:

private $_foo;
private $_bar;

public function __construct($foo,$bar) {
  $this->setFoo($foo);
  $this->setBar($bar);
}

public function setFoo($foo) {
  // validate here

  $this->_foo = $foo;
}

public function getFoo() {
  return $this->_foo;
}

...

这种方式更清洁......

答案 4 :(得分:0)

您的问题并非源于您正在编写面向对象的代码 - 这是因为PHP是loosely typed language。这意味着变量可以包含从int到Object的任何类型的数据。您可以强制执行某种类型的类型转换:

$foo = (int)$foo;
$bar = (str)$bar;

答案 5 :(得分:0)

在@ xil3的回答中详细说明我会说所有Dan都在寻找/需求是:

private $_foo;
private $_bar;

public function __construct($foo,$bar) {
  if(is_int($foo)) {
    $this->setFoo($foo);
  }
  if(is_string($bar)) {
    $this->setBar($bar);
  }
}

public function setFoo(int $foo) {
  $this->_foo = $foo;
}

public function setBar(string $bar) {
  $this->_foo = $bar;
}

...

允许他的对象在没有致命的情况下被实例化为无参数,并且对setter具有类型约束。

答案 6 :(得分:0)

除了在构造函数中设置值之外,您不应该做任何事情。如果您需要在(可能是私有的)setter中验证构造函数参数,或者使用特定类型的参数,那么PHP将为您验证类型,例如:

__construct(SomeType $foo, AnotherType $bar);

例如,您可以使用SPL数据类型:

__construct(SplInt $integer, SplString $string);

Read more about SPL data types

答案 7 :(得分:-1)

declare('strict_types=1');

public function __construct(
    int $foo, 
    string $bar, 
    Request $request // type hint even classes
) {
       $this->foo = $foo;
       $this->bar = $bar;
}