suin.io

Object→Arrayにキャストする ~多次元配列編~

suin2009年3月9日

PHPではオブジェクト型のメンバ変数を連想配列型にキャストすることができます。(See オブジェクトをarrayにキャストする - Do You PHP はてな:)

$fruit = new stdClass;
$fruit->apple = '150yen';
$fruit->orange = '170yen';

上の$fruit(array)すると、

echo 'An apple costs '.$fruit['apple'].'.';

というかんじで、普通に配列として振る舞えます。

stdClassでオブジェクトを作って、後で連想配列にするという手は意外と便利です。ちなみにstdClassはPHPの標準クラスです。なんの断りもなしにnewして使うことができます。

PHPでのオブジェクトは短い演算子->でメンバ変数を指定できるので、連想配列にするよりもコードがすっきりして個人的には好きです。逆に、Smartyの場合では、連想配列のキーをドット(.)で指し示すことができるので、オブジェクトで持つよりも連想配列で持った方がコードがきれいになります。

なので、PHPではオブジェクトにしておいて、Smartyに渡すところで連想配列にキャストするなんてことを たまにしたりします。

$fruitの例のように1次元の配列だと、(array)をかけるだけで、まるまる配列になりますが、階層が2段以上になるオブジェクトの場合は、(array)だと思うように多次元配列になりません。

アジアの都市の人口のデータのオブジェクトを例にあげて考えます。

$asia = new stdClass; // アジア都市の人口
$asia->japan->tokyo    = '12,909,940';
$asia->japan->osaka    = '8,834,433';
$asia->korea->seoul    = '10,421,782';
$asia->korea->busan    = '3,711,268';
$asia->china->beijing  = '17,430,000';
$asia->china->hongkong = '6,963,100';

単純にこれを var_dump($asia); すると、当たり前のように $asia も、その子の $japan, $korea, $china もオブジェクト型になっています。

object(stdClass)#4 (3) {
  ["japan"]=>
  object(stdClass)#5 (2) {
    ["tokyo"]=>
    string(10) "12,909,940"
    ["osaka"]=>
    string(9) "8,834,433"
  }
  ["korea"]=>
  object(stdClass)#6 (2) {
    ["seoul"]=>
    string(10) "10,421,782"
    ["busan"]=>
    string(9) "3,711,268"
  }
  ["china"]=>
  object(stdClass)#7 (2) {
    ["beijing"]=>
    string(10) "17,430,000"
    ["hongkong"]=>
    string(9) "6,963,100"
  }
}

次に、 var_dump((array)$asia); を試してみます。すると、$asia だけが配列になり、 $japan などはオブジェクトのままです。

array(3) {
  ["japan"]=>
  object(stdClass)#5 (2) {
    ["tokyo"]=>
    string(10) "12,909,940"
    ["osaka"]=>
    string(9) "8,834,433"
  }
  ["korea"]=>
  object(stdClass)#6 (2) {
    ["seoul"]=>
    string(10) "10,421,782"
    ["busan"]=>
    string(9) "3,711,268"
  }
  ["china"]=>
  object(stdClass)#7 (2) {
    ["beijing"]=>
    string(10) "17,430,000"
    ["hongkong"]=>
    string(9) "6,963,100"
  }
}

オブジェクトにオブジェクト内オブジェクトが...といりこ状になっているオブジェクトの場合は、再帰的に (array) をかける必要があります。便宜的に次のような関数を定義すると楽です。

function obj2arr($obj)
{
    if ( !is_object($obj) ) return $obj;

    $arr = (array) $obj;

    foreach ( $arr as &$a )
    {
        $a = obj2arr($a);
    }

    return $arr;
}

最後に、var_dump(obj2arr($asia)); を実行してみると、みごとにオブジェクトが多次元連想配列に置き換わります。

array(3) {
  ["japan"]=>
  array(2) {
    ["tokyo"]=>
    string(10) "12,909,940"
    ["osaka"]=>
    string(9) "8,834,433"
  }
  ["korea"]=>
  array(2) {
    ["seoul"]=>
    string(10) "10,421,782"
    ["busan"]=>
    string(9) "3,711,268"
  }
  ["china"]=>
  array(2) {
    ["beijing"]=>
    string(10) "17,430,000"
    ["hongkong"]=>
    string(9) "6,963,100"
  }
}
RELATED POSTS