PHP5.3.14以降のarray_walkで内部ポインタが破壊される


たぶんこれ bug だと思うので、PHPに詳しい人達に調べてもらいたい所ですが、最近のPHP5.3系と5.4系で array_walk() を使うと、その戻り値となる配列の内部ポインタ(internal array pointer)が壊れてしまうようです。

以下のコードは、配列に対して array_walk() を実行したあと、 current() でその配列のポインタを参照しています。このコードは、PHPのバージョンによって動作が変わります。

具体的には、PHP5.3.13で実行するとoが表示され、PHP5.4.17で実行するとxが表示されます。

いつの時点から挙動が変わっているのか知りたくなったので、PHP Sandbox, test PHP online, PHP tester を使って、各バージョン毎の差位を調べて表にしてみました。

version result
5.4.17 x
5.4.13 x
5.4.12 x
5.4.11 x
5.4.10 x
5.4.9 x
5.4.8 x
5.4.7 x
5.4.6 x
5.4.5 x
5.4.4 x
5.4.3 o
5.4.2 o
5.4.1 o
5.4.0 o
5.3.23 x
5.3.22 x
5.3.21 x
5.3.20 x
5.3.19 x
5.3.18 x
5.3.17 x
5.3.16 x
5.3.15 x
5.3.14 x
5.3.13 o
5.3.12 o
5.3.11 o
5.3.10 o
5.3.3 o
5.3.2 o
5.3.1 o
5.3.0 o
5.2.17 o
5.2.16 o
5.1.6 o
5.1.5 o
5.0.5 o
5.0.4 o
4.4.9 o

PHP5.4.3と、PHP5.3.13を最後に、挙動が変わってしまっているようです。

この挙動の変化を回避するには、 array_walk() の後に、 reset() を呼んで、明示的に内部ポインタを初期化してあげる事が必要です。

array_walk() のマニュアルには、「array_walk() is not affected by the internal array pointer of array.」 とあるので、 reset() しなくても良いのが正しい挙動だと思うのですが…

投稿者: halt

PHPプログラマ。

“PHP5.3.14以降のarray_walkで内部ポインタが破壊される” への 25 件のフィードバック

  1. ん?array_wolk() アウトなの?いろいろ放置だったから気付いてなかったけど、バージョンあげらんないじゃないか。

  2. 5.3.14から、内部ポインタを直接いじるように変更されている。https://github.com/php/php-src/commit/7ccd5943924fd4ad9adcad1fbc547adc79114bff

  3. 内部ポインタがリセットされないとのは別問題ですが、
    「array_walk() is not affected by the internal array pointer of array. array_walk() will walk through the entire array regardless of pointer position.」
    上記の2文目を考慮すると、
    「array_walk 後の内部ポインタに影響しない」ではなく、
    「array_walk 前の内部ポインタに影響しない」と解釈するのが自然だと思います。

  4. 内部ポインタに依存したプログラムって滅多に書かないからたぶん問題ないし、そもそも内部ポインタに依存したロジックにすべきではない。普通にイテレートする場合は自動的に rewind される。

  5. Zend Hash API が内部ポインターを外部 (HashPosition) から管理する ex 系の関数から内部管理系の ex なしの関数に変更されている。reset 関数に該当する zend_hash_internal_pointer_reset(target_hash) が追加されている。

  6. 内部ぽいんたでごにょごにょしてる最中に array_walk() かけるとかどんな状況なんだろ? foreach なんかだとるーぷ内で触るときけんがあぶないよって注意書きはあるけど・・・ (・x【みかん

  7. sandbox便利やんこれ。実際の仕様変更はこの際置いといて、docsの方は「内部ポインタがどこを指してようが、array_walkはその影響を受けずに(お構いなしに)全部の要素をwalkするよー」と読めるかな。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

ねこ認証:9つのパネルの中からねこを3匹選んでください