Phalcon\Config 配列マージを修正

  • KJ
  • 2015-03-10 13:25

Phalcon バージョン 2.0 の Phalcon\Config で配列をマージできなかったので修正しました。

Phalcon:2.0 にマージ済です。 Merge pull request #3338

挙動

修正前に挙動を確認します。

次のようなサンプルファイルを作成し、実行します。

test.php

<?php
namespace Phalcon;

$conf1 = ['keys' => ['scott', 'cheetah']];
$conf2 = ['keys' => ['peter']];

$config = new Config($conf1);
$config->merge(new Config($conf2));

var_dump($config->toArray());

このファイルの実行結果(修正前)は次のようになります。

Warning: Phalcon\Config::_merge(): Property should be string in test.php on line 8
array(1) {
  'keys'=>
  array(2) {
    [0]=>
    string(5) "scott"
    [1]=>
    string(7) "cheetah"
  }
}

PHP の Warning エラーが表示され、マージもできませんでした。

エラー原因

Phalcon\Config::_merge() 関数内のマージ処理でキーと値をオブジェクトとして処理しているため、配列の数字キーをオブジェクトのプロパティにセットしようとしてエラーになっているようです。

対策

数字キーのプロパティがエラーになっているので、キーが数字の場合は文字列にキャストしてから設定するようにすれば回避できるので、マージ処理の部分を

if typeof key == "integer" {
  let key = strval(key);
}
let instance->{key} = value;

のように変更してみます。

この時のテストコードの実行結果は次のようになります。

array(1) {
  'keys'=>
  array(2) {
    [0]=>
    string(5) "peter"
    [1]=>
    string(7) "cheetah"
  }
}

この結果は Phalcon 1 系のものと同じなのでこのままでもよいのですが、私としては array_merge_recursive を実行した時と同じような結果欲しいと考えました。

array_merge_recursive の実行結果は次のようになります。

var_dump(array_merge_recursive($conf1, $conf2));
/*
array(1) {
  'keys' =>
  array(3) {
    [0] =>
    string(5) "scott"
    [1] =>
    string(7) "cheetah"
    [2] =>
    string(5) "peter"
  }
}
*/

同じような結果を得るようにするために、マージする前にマージ先の配列数を確認し、マージ(追加)する時のキーを 配列数 + 1 になるようしてみます。

let number = instance->count();

..

if typeof key == "integer" {
  let key = strval(number);
  let number++;
}
let instance->{key} = value;

これで実行すると結果は次のようになりました。

array(1) {
  'keys' =>
  array(3) {
    [0] =>
    string(5) "scott"
    [1] =>
    string(7) "cheetah"
    [2] =>
    string(5) "peter"
  }
}

注意

単純に配列数を数えてからインクリメントしているだけなので、次のような配列をマージした場合

$conf1 = ['keys' => [ 'scott', 3 => 'cheetah', 'a' => 'b' ]];
$conf2 = ['keys' => ['peter']];

結果が

array(1) {
  'keys' =>
  array(3) {
    [0] =>
    string(5) "scott"
    [3] =>
    string(5) "peter"
    'a' =>
    string(1) "b"
  }
}

のようになり、欲しい結果が得られないかもしれないので注意してください。