web-dev-qa-db-ja.com

存在する配列要素にアクセスする際の未定義のオフセット

私は配列とPHPを持っており、それを印刷すると、アクセスする必要のある値を確認できますが、それらのキーでアクセスしようとすると、PHP注意。配列を print_r で出力しました:

_Array
(
    [207] => sdf
    [210] => sdf
)
_

インデックスを使用して配列にアクセスしようとすると、未定義のオフセット通知が表示されます。これが私のコードです:

_print_r($output); 
echo $output[207];   // Undefined Offset
echo $output["207"]; // Undefined Offset
_

_$output_配列は、 array_diff_key の呼び出しの結果であり、元々はHTTP POSTリクエストを介してJSONとして入力されます。

array_keys は私に次を与えます:

_Array
(
   [0] => 207
   [1] => 210
)
_

コメントに応えて:

var_dump(key($output));出力:

_   string(3) "207"
_

var_dump(isset($output[key($output)]));出力:

_   bool(false)
_
29
Kevin Rave

PHPマニュアル のオブジェクトを配列に変換する方法については、このセクションを参照してください。

キーはメンバー変数名ですが、いくつかの注目すべき例外があります。整数プロパティにアクセスできません;プライベート変数には、変数名の前にクラス名が付いています。保護された変数には、変数名の前に「*」が付いています。

PHPのオブジェクトから配列に変換する場合、整数配列キーは文字列として内部に格納されます。 PHPの配列要素にアクセスするか、通常どおり配列を使用すると、有効な整数を含むキーが自動的に整数に変換されます。文字列として内部に格納されている整数はアクセスできないキーです。

違いに注意してください:

$x = (array)json_decode('{"207":"test"}');
var_dump(key($x));  // string(3) "207"

var_dump($x);
// array(1) {
//   ["207"]=>
//   string(4) "test"
// }


$y['207'] = 'test';
var_dump(key($y));  // int(207)

var_dump($y);
// array(1) {
//   [207]=>
//   string(4) "test"
// }

print_r これらの配列の両方で同じ出力が得られますが、 var_dump を使用すると違いがわかります。

これがあなたの正確な問題を再現するいくつかのコードです:

$output = (array)json_decode('{"207":"sdf","210":"sdf"}');

print_r($output);
echo $output[207];
echo $output["207"];

そして、簡単な修正は、オプションのtrue引数に対してassocjson_decode に渡して、オブジェクトではなく配列が必要であることを指定することです。

$output = json_decode('{"207":"sdf","210":"sdf"}', true);

print_r($output);
echo $output[207];
echo $output["207"];
25
Paulpro

この問題は、有効な整数である文字列キーを持つオブジェクトをarrayキャスト すると発生します。

このオブジェクトがある場合:

_object(stdClass)#1 (2) {
  ["207"]=>
  string(3) "sdf"
  ["210"]=>
  string(3) "sdf"
}
_

そしてあなたはそれをキャストします

_$array = (array)$object
_

この配列を取得します

_array(2) {
  ["207"]=>
  string(3) "sdf"
  ["210"]=>
  string(3) "sdf"
}
_

_$array["207"]_のような直接アクセスは常に 変換 されて_$array[207]_になりますが、これは存在しないため、ループすることによってのみアクセスできるキーがあります。 。

json_decode()から上記のようなオブジェクトを次のような文字列に適用しているので

_$json = '{"207":"sdf", "210":"sdf"}'
_

最善の解決策は、そもそも数字キーを避けることです。これらはおそらく、オブジェクトの配列の数値プロパティとしてより適切にモデル化されます。

_$json = '[{"numAttr":207, "strAttr":"sdf"}, {"numAttr":210, "strAttr":"sdf"}]'
_

このデータ構造には、現在のものに比べていくつかの利点があります。

  1. 数値プロパティを持つオブジェクトのコレクションとして、元のデータをより適切に反映します
  2. 他のプロパティで簡単に拡張できます
  3. さまざまなシステム間での移植性が高くなっています(ご覧のとおり、現在のデータ構造がPHPで問題を引き起こしていますが、別の言語を使用した場合、同様の問題が発生する可能性があります)。

プロパティ→オブジェクトマップが必要な場合は、次のようにすばやく取得できます。

_function getNumAttr($obj) { return $obj->numAttr; } // for backward compatibility
$arr = json_decode($json); // where $json = '[{"numAttr":...
$map = array_combine(array_map('getNumAttr', $arr), $arr);
_

もう1つの解決策は、ascii-Limeが提案したように実行することです。2番目のパラメーターをtrueに設定して、 json_decode() にオブジェクトではなく連想配列を出力させます。

_$map = json_decode($json, true);
_

入力データの場合、これは直接生成します

_array(2) {
  [207]=>
  string(3) "sdf"
  [210]=>
  string(3) "sdf"
}
_

配列のキーが文字列ではなく整数になっていることに注意してください。

JSONデータ構造を変更することは不可能かもしれないと理解していますが、もっとクリーンなソリューションを検討したいと思います。

20
Walter Tross

試してみてください

var_dump($output);
foreach ($output as $key => val) {
    var_dump($key);
    var_dump($val);
}

何が起こっているかについてもっと学ぶために。

どのような正確な行/ステートメントが警告を投げていますか?

1
Aron Cederholm

このバグ を見つけたところ、 nserialize の呼び出しによって配列が作成されると、PHP)で配列要素にアクセスできなくなることがあります。 。

次のスクリプトを含む(またはコマンドラインから実行する)テストPHPファイルを作成します。

<?php 

$a = unserialize('a:2:{s:2:"10";i:1;s:2:"01";i:2;}'); 

print $a['10']."\n";

$a['10'] = 3; 
$a['01'] = 4; 

print_r($a);

foreach ($a as $k => $v) 
{ 
  print 'KEY: '; 
  var_dump($k); 
  print 'VAL: '; 
  var_dump($v); 
  print "\n"; 
}

エラーが発生した場合は、PHPのバージョンにこのバグが含まれているため、PHP 5.3にアップグレードすることをお勧めします。

1
Paulpro

私のアプローチを使用してみてください:

class ObjectToArray {
    public static function convert( $object ) {
        if( !is_object( $object ) && !is_array( $object ) ) {
            return $object;
        }

        if( is_object( $object ) ) {
           $object = get_object_vars( $object );
        }

        return array_map( 'ObjectToArray::convert', $object );
    }
}

$aNewArray = ObjectToArray::convert($oYourObject);
0
Maykonn

配列をどのように印刷しましたか? print_r($arrayName);をお勧めします

次に、次のような個々の要素を印刷できます。echo $arrayName[0];

0
blearn