たぶんこれ 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() しなくても良いのが正しい挙動だと思うのですが…

カテゴリー:

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

  1. ockeghem より:

    PHP5.5.0, 5.5.1で確認しても x でした。

  2. ayatorch より:

    みてる: PHP5.3.14以降のarray_walkで内部ポインタが破壊される | この先生きのこるには

  3. ya--mada より:

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

  4. tmatsuu より:

    PHP Sandbox知らなかった。便利だねぇ

  5. manaten より:

    内部ポインタ自体、怖くてあまり使わないな・・・

  6. barelo より:

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

  7. phper より:

    内部ポインタがリセットされないとのは別問題ですが、
    「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 前の内部ポインタに影響しない」と解釈するのが自然だと思います。

  8. manaplus より:

    便利なんだけれどね・・触らぬ神に祟りなしか

  9. escape_artist より:

    まあforeach使えばいいよね

  10. Chisei より:

    PHP Sandboxに目が行った

  11. syanbi より:

    テストを重厚にしよう

  12. somemo より:

    array_map使えばと思ったけど、recursiveもかな?と疑問に思った[php]

  13. ktakemoto より:

    どうしようもなさ

  14. typex2 より:

    # |ω・)…… イヤな予感。。

  15. trashtoy より:

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

  16. shin1x1 より:

    「array_walk() は array の内部配列ポインタに影響されません。」なので、array_walk()後の内部ポインタがどうなるかは明言されていないかと。 http://jp1.php.net/manual/ja/function.array-walk.php

  17. masakielastic2 より:

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

  18. ngyuki より:

    配列の内部ポインタに依存する処理は書かないほうが無難

  19. mumincacao より:

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

  20. taka222 より:

    ”PHP5.3.14以降のarray_walkで内部ポインタが破壊される | この先生きのこるには”

  21. oppara より:

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

  22. shimooka より:

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

コメントを残す

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

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