我正在检查PHP中的可选参数类型:
/**
* Get players in the team using limit and
* offset.
*
*
* @param TeamInterface $participant
* @param int $limit
* @param int $offset
* @throws \InvalidArgumentException
* @return Players of a team
*/
public function getPlayers(TeamInterface $team, $limit = null, $offset = null)
{
if (func_num_args() === 2 && !is_int($limit) ){
throw new \InvalidArgumentException(sprintf('"Limit" should be of int type, "%s" given respectively.', gettype($limit)));
}
if (func_num_args() === 3 && (!is_int($limit) || !is_int($offset))){
throw new \InvalidArgumentException(sprintf('"Limit" and "Offset" should be of int type, "%s" and "%s" given respectively.', gettype($limit), gettype($offset)));
}
//.....
}
这有效,但有两个主要问题:
1 /如果我需要检查相同int
类型的4/5可选参数的类型,则代码变得不必要地长。任何想法如何使这段代码更易于维护? (也许只使用一个if
语句来检查同一类型的$limit
和$offset
)
2 / getPlayers($team, 2, null)
抛出异常。知道函数实际上可以在这里处理null
值吗?
答案 0 :(得分:2)
你可以使用args数组进行for循环。类似的东西:
$args = func_get_args();
for ($i = 1; $i < 4; $i++) {
if ($args[$i] !== null and !is_int($args[$i])) {
throw ...
}
}
当然,根据您需要检查的参数数量调整for条件。
或者...
$args = func_get_args();
// skip first
array_shift($args);
foreach ($args as $arg) {
if ($arg !== null and !is_int($arg)) {
throw ...
}
}
答案 1 :(得分:1)
对于1)我会单独检查每个变量并为每个变量抛出异常:
if (!is_int($limit)){
//Throw
}
if (!is_int($offset))){
//Throw
}
这仍然需要每个变量的if语句,但是不那么冗长。
对于2)如果允许空值,您可以将检查更改为:
if ($offset && !is_int($offset))){
//Throw
}
最后,我不建议您查看func_num_args()
。在您的示例代码中,使用太多参数调用函数将绕过验证。
答案 2 :(得分:1)
我个人更喜欢每个函数只有一个参数(除非函数非常简单),例如函数可以取$request
,并返回一个数据树$response
。它使循环和扩展更容易一些:
function dostuff( $request ) {
$team = @$request['team'];
$limit = @$request['limit'];
$offset = @$request['offset'];
// ...
return $response;
}
然后,为了验证,您可以在函数顶部编写一组规则,如
// define validation rules
$rules = array( 'required' => array('team'),
'depends' => array('offset' => 'limit'),
'types' => array('offset' => 'int', 'limit' => 'int' ),
);
在一次通话中集中所有错误检查:
// can throw exception
argcheck( array( 'request' => $request, 'rules' => $rules ) );
这可能需要优化,但一般方法有助于在增加函数的复杂性时包含膨胀。
答案 3 :(得分:1)
PHP还没有标量的类型提示。
当您开始在函数中使用大量可选参数时,您会产生代码味道。有些东西是错的,有一个物体在等待出现。
将所有可选参数构建为Object并在其上设置验证方法。
我认为你想要一个GameParameters对象,并且有一个验证方法。
getPlayers($gameParameters) {
}
将参数验证移至该对象,您可以将其构建到每个setter中,或者具有全面的validate()函数。
就检查的爆炸性而言,我会构建一个错误数组,如果有错误则扔掉它。这可以在重新设计或不重新设计的情况下完成。
if ($limit != null && !is_int($limit){
#add to the errors array
}
if ($offset != null && !is_int($offset){
#add to the errors array
}
if (errors) {
throw new \InvalidArgumentException(sprintf('"Limit" and "Offset" should be of int type, "%s" and "%s" given respectively.', gettype($limit), gettype($offset)));
}
答案 4 :(得分:0)
使用开关编码特定功能。
switch(gettype($limit)) {
case "integer":
//do other processing
break;
}
你不能让你的代码容易受到攻击。至于克服漏洞的安全解决方案。创建一个这样的安全列表。
public function getPlayers(TeamInterface $team, $limit = null, $offset = null) {
$safelist = array("var1" => "TeamInterface", "var2" => "integer", "var3" => "integer");
$args = function_get_args();
$status = true;
foreach($args as $key => $var) {
if(gettype($var)!=$safelist["var".$key]) {
$status = false;
break;
}
}
if(!$status) break;
//...........
}