filter_input_array / filter_var_array の挙動がマニュアルの表記と違う件

# 3行で

[filter_input_array]とか[filter_var_array]が
使い物にならないと思ってたけど実はそうでもなかった
ちゃんと確認せず記事書いてごめんなさい

# 問題

以下の記事を既に読まれている人向けです．

- [$_GET, $_POSTなどを受け取る際の処理](http://qiita.com/mpyw/items/2f9955db1c02eeef43ea)
- [PHP7で流行って欲しいリクエストパラメータの受け取り方](http://qiita.com/mpyw/items/25abc3e51fddc85e0ec0)

## マニュアルの表記

[filter_input_array]のマニュアルの記述を見ると，以下のようなものがある．

```php:例1&#32;filter_input_array()&#32;の例

<?php
error_reporting(E_ALL | E_STRICT);
/* データは、実際には POST リクエストでやってきます
$_POST = array(
    'product_id'    => 'libgd<script>',
    'component'     => '10',
    'versions'      => '2.0.33',
    'testscalar'    => array('2', '23', '10', '12'),
    'testarray'     => '2',
);
*/

$args = array(
    'product_id'   => FILTER_SANITIZE_ENCODED,
    'component'    => array('filter'    => FILTER_VALIDATE_INT,
                            'flags'     => FILTER_REQUIRE_ARRAY, 
                            'options'   => array('min_range' => 1, 'max_range' => 10)
                           ),
    'versions'     => FILTER_SANITIZE_ENCODED,
    'doesnotexist' => FILTER_VALIDATE_INT,
    'testscalar'   => array(
                            'filter' => FILTER_VALIDATE_INT,
                            'flags'  => FILTER_REQUIRE_SCALAR,
                           ),
    'testarray'    => array(
                            'filter' => FILTER_VALIDATE_INT,
                            'flags'  => FILTER_REQUIRE_ARRAY,
                           )

);

$myinputs = filter_input_array(INPUT_POST, $args);

var_dump($myinputs);
echo "\n";
?>
```

```php:上の例の出力は以下となります。
array(6) {
  ["product_id"]=>
  array(1) {
    [0]=>
    string(17) "libgd%3Cscript%3E"
  }
  ["component"]=>
  array(1) {
    [0]=>
    int(10)
  }
  ["versions"]=>
  array(1) {
    [0]=>
    string(6) "2.0.33"
  }
  ["doesnotexist"]=>
  NULL
  ["testscalar"]=>
  bool(false)
  ["testarray"]=>
  array(1) {
    [0]=>
    int(2)
  }
}
```

## 実際の出力

ところが実際はこうはならない．

```php:実際の出力
array(6) {
  ["product_id"]=>
  string(17) "libgd%3Cscript%3E"
  ["component"]=>
  bool(false)
  ["versions"]=>
  string(5) "2.2.3"
  ["doesnotexist"]=>
  NULL
  ["testscalar"]=>
  bool(false)
  ["testarray"]=>
  bool(false)
}
```

## 疑問点

### `testarray`が配列キャストではなく`bool(false)`となる点

`FILTER_FORCE_ARRAY`と書こうとして，誤って`FILTER_REQUIRE_ARRAY`と書いてしまっているから，であると推測できる．これは単なるドキュメントの不備として見てもいい．この点に関しては，今まで特に感じていたことは無かった．

### `product_id`や`versions`が配列ではなく文字列になる点

この記事の本題．**バリデーション成功時に配列になるのが`filter_input_array`や`filter_var_array`特有の挙動**ということで納得していた．自分の記憶では，実際にこれを動作させて確認したことになっていた．

…ところが，今確認してみると自分の記憶と矛盾した出力が発生した．さすがにおかしいぞ，と思ってPHP5.2.17という太古の環境をわざわざ用意して確認してみたが，おかしいのは自分の記憶のほうだった．

# これからどうすればいいか

**「そもそもバリデータとか普通フレームワークで用意されたやつ使うしこんな関数使わないっしょｗ」**

…というのは尤もな意見だが，あくまでそういったものに頼らないという前提で書くと

```php:filter_inputでスカラーを処理
$params = [
    'nickname' => filter_input(INPUT_POST, 'nickname'),
    'email' => filter_input(INPUT_POST, 'nickname', FILTER_VALIDATE_EMAIL),
    'age' => filter_input(INPUT_POST, 'age', FILTER_VALIDATE_INT, [
        'options' => [
            'min_range' => 0,
            'max_range' => 100,
        ],
    ]),
];
```

```php:filter_input_arrayでスカラーを処理
$params = filter_input_array(INPUT_POST, [
    'nickname' => [],
    'email' => FILTER_VALIDATE_EMAIL,
    'age' => [
        'filter' => FILTER_VALIDATE_INT,
        'options' => [
            'min_range' => 0,
            'max_range' => 100,
        ],
    ],
]);
```

このようなコードは書ける．`(string)`キャストのようなものを入れない場合は後者のほうがいいかもしれない．しかし，配列の処理になると…

```php:filter_inputで配列を処理
$params = [
    'hobbies' => filter_input(INPUT_POST, 'hobbies', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY)
];
```

```php:filter_input_arrayで配列を処理
$params = filter_input_array(INPUT_POST, [
    'hobbies' => ['flags' => FILTER_REQUIRE_ARRAY],
]);
```

これらのコードはいずれとも

- 配列の強制ができない<br>**(`FILTER_FORCE_ARRAY`にしても未定義時にはNULLにされてしまう)**
- 配列の階層数の指定ができない<br>

など大きな欠点があるため，実用的ではない．結局，

- [filter_input_array_recursive](http://qiita.com/mpyw/items/c39b9ee695a5c2e74627)のような関数を作る
- フレームワークのバリデータを信じてそちらに丸投げする

というところに落ち着くのである．

[filter_input_array]: http://www.php.net/manual/ja/function.filter-input-array.php
[filter_var_array]: http://www.php.net/manual/ja/function.filter-var-array.php