LoginSignup
6
1

More than 5 years have passed since last update.

PHPのrangeが値を返さない場合がある

Posted at

最近は業務でPHPを触っている毎日です。暗黙の型変換等々に苦しめられながら頑張っています。

今回はrange()にやられました。

range()とは

array range ( mixed $start , mixed $end [, number $step = 1 ] )
ある範囲の整数を有する配列を作成します。

よくある関数です。
始めの値と終わりの値とステップ数を指定して、それにあった配列を返してくれます。
foreach()と組み合わせて使ったりするナイスガイです。

何が起きたのか

次のようなサンプルがあったとして、実行してみます。

sample.php
foreach(range(1, 16, 2) as $index)
{
    $logger->info('range index: ' . $index);
}
$logger->info('range array count: ' . count(range(1, 16, 2)));
$logger->info('range array 0: ' . range(1, 16, 2)[0]);
sample.php結果
[2018-06-29 11:51:24] app.INFO: range index: 1 [] []
[2018-06-29 11:51:24] app.INFO: range index: 3 [] []
[2018-06-29 11:51:24] app.INFO: range index: 5 [] []
[2018-06-29 11:51:24] app.INFO: range index: 7 [] []
[2018-06-29 11:51:24] app.INFO: range index: 9 [] []
[2018-06-29 11:51:24] app.INFO: range index: 11 [] []
[2018-06-29 11:51:24] app.INFO: range index: 13 [] []
[2018-06-29 11:51:24] app.INFO: range index: 15 [] []
[2018-06-29 11:51:24] app.INFO: range array count: 8 [] []
[2018-06-29 11:51:24] app.INFO: range array 0: 1 [] []

期待通りの結果ですね。素晴らしいです。

では次のサンプルはどうでしょうか。

sample2.php
foreach(range(8, 10, 3) as $index)
{
    $logger->info('range index: ' . $index);
}
$logger->info('range array count: ' . count(range(8, 10, 3)));
$logger->info('range array 0: ' . range(8, 10, 3)[0]);
sample2.php結果
[2018-06-29 11:55:09] app.INFO: range array count: 1 [] []
[2018-06-29 11:55:09] app.INFO: range array 0:  [] []

……えっ。なにこれ。

count()1ということは値は返ってきているのでしょうか。
いえいえrange(8, 10, 3)[0]の結果が空なので、そもそもうまく動いている感じがしません。
ちょっといろいろ調べてみましょう。

調査

単一の値の配列の場合、そもそもforeach()はループしてくれるのでしょうか。

sample3.php
foreach([8] as $index)
{
    $logger->info('range index: ' . $index);
}
$logger->info('range array count: ' . count([8]));
$logger->info('range array 0: ' . [8][0]);
sample3.php結果
[2018-06-29 12:07:48] app.INFO: range index: 8 [] []
[2018-06-29 12:07:48] app.INFO: range array count: 1 [] []
[2018-06-29 12:07:48] app.INFO: range array 0: 8 [] []

ループしてくれますね。ということはsample2.phpはやはり値が返ってない感じがします。

ちょっとrange()の値を変えて試してみましょう。
開始と終わりの数を同じにしてみます。

sample4.php
foreach(range(8, 8, 1) as $index)
{
    $logger->info('range index: ' . $index);
}
$logger->info('range array count: ' . count(range(8, 8, 1)));
$logger->info('range array 0: ' . range(8, 8, 1)[0]);
sample4.php結果
[2018-06-29 12:09:32] app.INFO: range index: 8 [] []
[2018-06-29 12:09:32] app.INFO: range array count: 1 [] []
[2018-06-29 12:09:32] app.INFO: range array 0: 8 [] []

これは問題ありませんね。
では次。終わりを9に、ステップ数を2に変えます。

sample5.php
foreach(range(8, 9, 2) as $index)
{
    $logger->info('range index: ' . $index);
}
$logger->info('range array count: ' . count(range(8, 9, 2)));
$logger->info('range array 0: ' . range(8, 9, 2)[0]);
sample5.php結果
[2018-06-29 12:14:55] app.INFO: range array count: 1 [] []
[2018-06-29 12:14:55] app.INFO: range array 0:  [] []

発生しましたね。
次は終わりを8に変えてみましょう。

sample6.php
foreach(range(8, 8, 2) as $index)
{
    $logger->info('range index: ' . $index);
}
$logger->info('range array count: ' . count(range(8, 8, 2)));
$logger->info('range array 0: ' . range(8, 8, 2)[0]);
sample6.php結果
[2018-06-29 12:18:20] app.INFO: range index: 8 [] []
[2018-06-29 12:18:20] app.INFO: range array count: 1 [] []
[2018-06-29 12:18:20] app.INFO: range array 0: 8 [] []

発生しません。なんとなく発生する条件がわかってきました。

結果

どうやら、次の条件を満たしているとrange()がうまく働かなさそうなことがわかりました。

array range ( mixed $start , mixed $end [, number $step = 1 ] )

  • \$end > \$start
  • \$start + \$step > \$end

PHP5.6で試したので、もしかしたら7だと解決しているのかもしれません。

ちょっとこれでひどい目にあったので、共有まで。

6
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1