こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

array_mapの再帰処理がうまく行かない

長文で失礼します。
array_mapでの再帰処理がうまく行かないのでどこが間違っているか教えてください。

まず、このような配列があります。配列の中に配列があります。

$ary = array(1, 2, null, array("a", null, "c"));

この配列の中のnullを"なし"という文字列に変換したいです。
array_mapを使って再帰的にやってみました。
まずはうまく行ったコードから。

------------------------------------------------------
$ary = array(1, 2, null, array("a", null, "c"));
var_dump(null2Nashi($ary));

// nullを"なし"に置換する関数
function null2Nashi(
 $in_array
){
 if(is_array($in_array)){
  return array_map("null2Nashi", $in_array);
 } else {
  if ($in_array === null){
   $in_array = "なし";
  }
  return $in_array;
 }
}
------------------------------------------------------
結果はnullが"なし"に変換されました

array (size=4)
 0 => int 1
 1 => int 2
 2 => string 'なし' (length=6)
 3 =>
  array (size=3)
   0 => string 'a' (length=1)
   1 => string 'なし' (length=6)
   2 => string 'c' (length=1)

そしてこの"なし"をコード内で指定するのではなく引数で指定したいと思って無名関数を使って以下のコードにしました。
------------------------------------------------------
$ary = array(1, 2, null, array("a", null, "c"));
var_dump(null2Str($ary, "なし"));

// nullを指定文字列に置換する関数
function null2Str(
 $in_array,// null値を含む配列
 $in_str// null値を変換したい文字列
){
 $n = function($n_array) use($in_str){
  if(is_array($n_array)){
   return array_map($n, $n_array); //…(1)
  } else {
   if ($n_array === null){
    $n_array = $in_str;
   }
   return $n_array;
  }
 };
 return $n($in_array);
}
------------------------------------------------------
結果はnullは何も変換されませんでした。

array (size=4)
 0 => int 1
 1 => int 2
 2 => null
 3 =>
  array (size=3)
   0 => string 'a' (length=1)
   1 => null
   2 => string 'c' (length=1)

どうやら(1)のarray_mapが動作していないようです。要素を分解せずに$nの無名関数に渡さずにそのまま第2引数を返しているだけみたいです。
何か対応方法があるでしょうか?

どうぞよろしくお願い致します。

投稿日時 - 2014-03-11 00:45:18

QNo.8508711

すぐに回答ほしいです

質問者が選んだベストアンサー

あー、なんで誤りに気づかなかったか分かりました。php.iniの設定で一部のエラーが隠蔽されているからです。おそらく

error_reporting = E_ALL & ~E_NOTICE

になっているんじゃないですかね。ところがE_NOTICEはデバッグ上非常に重要なエラーで、これを隠蔽してしまうことはデバッグ作業を困難にします。よって

error_reporting = E_ALL | E_STRICT

にしてすべてのエラーを表示させてください。恒久的ではなく、PHPスクリプト実行中に一時的に変更したい場合はerror_reporting関数を使って

error_reporting(E_ALL | E_STRICT);

としてください。また、下記リンクで未定義とNULLの違いの再確認をお願いします。

Qiita - 【PHP入門講座】 NULLと未定義の違い
http://qiita.com/mpyw/items/0a4ea0bc9a695da33f0c

さて、先ほどのコードを実行してみると分かるのですが

http://ideone.com/ZrWoN2

このように

PHP Notice: Undefined variable: n

が発生してしまっていますね。そしてその部分はNULLと見なされ、一見array_mapのコールが失敗するように思われるのですが…実は、array_mapはNULLも第1引数に取ることが出来るのです。

PHP Manual - array_map
http://php.net/manual/ja/function.array-map.php

以上の例4が該当しますね。

投稿日時 - 2014-03-11 12:16:44

お礼

ありがとうございます!
たしかにerror_reporting = E_ALL & ~E_NOTICEとしていました…。
NULLと未定義の件も了解しました。
今回の件でいろいろ見直したほうが良さそうですね。
重ね重ねお礼を申し上げます。

投稿日時 - 2014-03-12 05:14:01

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(3)

ANo.2

既存のコードのuse句での受け渡しについてですが、これだと無名関数スコープ内から無名関数自身を参照することが出来ないので、

$n = function($n_array) use($in_str) { ... }

としている部分を

$n = function($n_array) use($in_str, &$n) { ... }

にする必要があります。

投稿日時 - 2014-03-11 11:57:59

お礼

ありがとうございます!
無名関数の部分、そうだったのですね・・・。
たしかにuse($in_str, &$n)としましたらうまく動作しました。
これはちょっと気づかなかったです。

投稿日時 - 2014-03-12 05:12:21

ANo.1

反則技かもしれませんが、array_walk_recursiveではダメですか?array_mapは値を返す関数ですが、array_walk・array_walk_recursiveは参照渡しで値を編集する関数ですね。array_walkはforeachとほとんど出来ることに差はないですが、array_walk_recursiveは単純なforeachには出来ない強力な特長を持っています。

$array = array(1, 2, null, array('a', null, 'c'));
array_walk_recursive($array, function (&$v) {
 if ($v === null) {
  $v = 'なし';
 }
});

投稿日時 - 2014-03-11 11:52:09

お礼

ありがとうございます!
array_walk_recursive、知らなかったです。
PHPは本当に便利な関数が多いですね。
これを機にもっと勉強しようと思います^^

投稿日時 - 2014-03-12 05:07:11

あなたにオススメの質問