编写我的第一个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编程的概念对我来说是一个新手,所以非常感谢您对任何参考资料的链接。
答案 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);
答案 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;
}