PHPの配列キーとしての数値文字列


104

"123"整数に変換せずに、PHP配列のキーとして数値文字列を使用することはできますか?

$blah = array('123' => 1);
var_dump($blah);

プリント

array(1) {
  [123]=>
  int(1)
}

が欲しいです

array(1) {
  ["123"]=>
  int(1)
}

7
PHPは緩やかに型付けされているため、"123"== 123はほとんどすべての目的に使用できます。それを文字列として具体的に必要とする理由は何ですか(そしてintを持つことは悪いことです)?
ircmaxell 2010年

17
私の頭に浮かぶ理由は、array_merge 「入力配列に同じ文字列キーがある場合、そのキーの新しい値が前のキーを上書きすることになります。ただし、配列に数値キーが含まれている場合、新しい値は元の値を上書きしますが、追加されます。」
ficuscr 2014年

8
配列キーとして数値文字列が問題となる別の例:asort
swenedo


4
別のユースケース:JSONデータ遷移の単体テスト。このような配列をJSONに変換してから元に戻すと、元の結果と結果がまったく同じであると断言できなくなります。
David

回答:


90

番号; いいえ、ちがいます:

マニュアルから:

キーは整数または文字列のいずれかです。キーが整数の標準表現である場合、そのように解釈されます(つまり、「8」は8と解釈され、「08」は「08」と解釈されます)。

補遺

以下のコメントのため、動作はJavaScriptオブジェクトキー似ていますが同一ではないことを指摘するのは楽しいと思います。

foo = { '10' : 'bar' };

foo['10']; // "bar"
foo[10]; // "bar"
foo[012]; // "bar"
foo['012']; // undefined!

107
PHP、サーバー側のIE。
Marek Maurizio

5
実際に道があるようです!この回答に同意しませんか?stackoverflow.com/a/35180513/247696
Flimm

1
どうして?!.. foo [012] return "bar"
Himanshu

2
@Himanshu:phpは0で始まる数値を8進数として解釈するため。その012は進10です
YeasirアラファトMajumder

49

はい、stdClassオブジェクトを配列キャストすることで可能です:

$data =  new stdClass;
$data->{"12"} = 37;
$data = (array) $data;
var_dump( $data );

それはあなたに(PHPバージョン7.1まで)与える:

array(1) {
  ["12"]=>
  int(37)
}

(更新:私の元の答えは、使用することでより複雑な方法を示しましたがjson_decode()json_encode()これは必要ありません。)

コメントに注意してください。残念ながら、値を直接参照することはできません$data['12']。通知が表示されます。

更新
PHP 7.2以降では、数値文字列をキーとして使用して値を参照することもできます。

var_dump( $data['12'] ); // int 32

2
ただし、文字列キーを使用して値に直接アクセスすることはできません。この行を例に追加してください:echo $data['12'];。「通知:未定義のオフセット:12インチ-5行目」というエラーが表示されます。
LS 2016年

1
Uがlaravel dd($ data)を使用すると、クラッシュします:P
KamilKiełczewski

2
PHP 7.2.0RC2では、動作は以前と同じです。
dev0 '19

1
どうやらarray_key_existsそれは古いバージョンでも見つかりません。
パニックにならないでください。

1
PHP

12

PHPデータ構造で数値キーを使用する必要がある場合、オブジェクトは機能します。また、オブジェクトは順序を保持するため、反復処理が可能です。

$obj = new stdClass();
$key = '3';
$obj->$key = 'abc';

これは非常に良い提案です。私はフレームワークのコードを書いていて、「偶発的な」インデックス付けを持つ可能性のある配列を渡す誰かに直面しています:array( 'this'、 'that')または「連想」インデックス付け:array(123 => array( 'this'、 'that '))。今、あなたのおかげで、私はただタイプヒントを付けることができます;)+1
Just Plain High

しかし、整数に変換せずに、「123」のような数値文字列をPHP配列のキーとして使用することは可能ですか?
Flimm

@Flimmいいえ、それは不可能です。そのため、私は自分のソリューションを提供します。
16

@Flimmその答えは矛盾するよう手動でPHPを有効な整数を含む文字列は、整数型にキャストされます。たとえば、キー「8」は実際には8の下に格納されます。一方、「08」は有効な10進整数ではないため、キャストされません。、私は彼の答えをテストしていませんが。
16

その文は、「で指定しているarray()ので、そのコンテキストは、有効な整数を指定する文字列が整数型にキャストされると想定しています。しかし、配列が作成されない方法が他にもあることがわかりますそのような私がテストしているデビッドの答え、のように。
Flimm

10

私の回避策は:

$id = 55;
$array = array(
  " $id" => $value
);

スペース変換(プリペンド)は、int変換を維持するため、優れたソリューションです。

foreach( $array as $key => $value ) {
  echo $key;
}

55がintとして表示されます。


4
または"0$id" => $value0作品の先頭にも。
nawfal

つまり、整数に変換しないと、「123」のような数値文字列をPHP配列のキーとして使用することはできないということですか。
Flimm

5

キーを文字列に型キャストすることはできますが、PHPのルーズタイピングにより、最終的には整数に変換されます。自分で見て:

$x=array((string)123=>'abc');
var_dump($x);
$x[123]='def';
var_dump($x);

PHPマニュアルから:

キーは整数または文字列のいずれかです。キーが整数の標準表現である場合、そのように解釈されます(つまり、「8」は8と解釈され、「08」は「08」と解釈されます)。キーの浮動小数点数は整数に切り捨てられます。インデックス付きの連想配列型はPHPと同じ型で、整数と文字列の両方のインデックスを含めることができます。


1
変換は緩い入力によるものではありません。phpは、文字列数値に見えるかどうかを判断し、変換します。
ジャック

1
それは不可能だと言っているのですか?この回答は、整数のように見える文字列を配列のキーとして使用する方法があることを示しています。
Flimm

私見問題はPHPインタープリターです。文字列と整数を配列キーとして混在させる言語を想像することもできません。最善の解決策は?Undologによって提案されたように、stackoverflow.com / a / 15413637/1977778 の最善の解決策は、末尾のスペースを使用することです...悲しいことに。
センテンザ

@sentenza:ある PHPは配列のキーとして文字列と整数の混合物を可能にする、特に以来、想像することが可能に:[42 => 'answer', 'snafu' => 'fubar']
LS

@LSはい。PHPではそれが可能であることは知っていますが、架空のジェネリック型システム内のキーを考えると、文字列と数値を同時に含む混合型とは一致しません。ルーズタイピング連想配列のキーに適用される単に傾向誤差です。
センテンザ2016年

1

文字列と整数の両方のキーを持つ配列をマージしようとすると、この問題が発生しました。これらは入力フィールドの名前(靴のサイズなど)であるため、整数も文字列として処理されることが重要でした。

$data = array_merge($data, $extra);PHP を使用すると、キーが「再配列」されます。順序付けを行う試みでは、整数キーは、(私が試した6- '6'- "6"でも(string)"6"キーとして)に0から名前を変更してしまったnあなたが考えてみれば、ほとんどの場合、これは望ましい動作だろう...。

$data = $data + $extra;代わりにを使用してこれを回避できます。かなり簡単ですが、最初は考えていませんでした^^。


まったく同じ問題がこのページに私を導きましたが、これはOPの質問への答えではないと言う必要があります。
Flimm

@Flimm True。しかし、答えを探してこのページに行きました。私の解決策が他のGoogle社員の役に立つかもしれないと思った:)
Brainfeeder

1

有効な整数を含む文字列は、整数型にキャストされます。たとえば、キー「8」は実際には8の下に格納されます。一方、「08」は有効な10進整数ではないため、キャストされません。

違う

私は連想配列の連想配列キャストを処理するキャスト関数を持っています、

$array_assoc = cast($arr,'array_assoc');

$array_sequential = cast($arr,'array_sequential');

$obj = cast($arr,'object');

$json = cast($arr,'json');



function cast($var, $type){

    $orig_type = gettype($var);

    if($orig_type == 'string'){

        if($type == 'object'){
            $temp = json_decode($var);
        } else if($type == 'array'){
            $temp = json_decode($var, true);
        }
        if(isset($temp) && json_last_error() == JSON_ERROR_NONE){
            return $temp;
        }
    }
    if(@settype($var, $type)){
        return $var;
    }
    switch( $orig_type ) {

        case 'array' :

            if($type == 'array_assoc'){

                $obj = new stdClass;
                foreach($var as $key => $value){
                    $obj->{$key} = $value;
                }
                return (array) $obj;

            } else if($type == 'array_sequential'){

                return array_values($var);

            } else if($type == 'json'){

                return json_encode($var);
            }
        break;
    }
    return null; // or trigger_error
}

PHP

1

回避策として、JSON_FORCE_OBJECTオプションを使用して、PHP配列をjsonオブジェクトにエンコードできます。

つまり、この例:

     $a = array('foo','bar','baz');
     echo "RESULT: ", json_encode($a, JSON_FORCE_OBJECT);

結果は:

     RESULT: {"0" : "foo", "1": "bar", "2" : "baz"}

0

'0'と ''の両方をキーとして持つ配列でこの問題に遭遇しました。これは、==または===で配列キーをチェックできなかったことを意味します。

$array=array(''=>'empty', '0'=>'zero', '1'=>'one');
echo "Test 1\n";
foreach ($array as $key=>$value) {
    if ($key == '') { // Error - wrongly finds '0' as well
        echo "$value\n";
    }
}
echo "Test 2\n";
foreach ($array as $key=>$value) {
    if ($key === '0') { // Error - doesn't find '0'
        echo "$value\n";
    }
}

回避策は、使用する前に配列キーを文字列にキャストバックすることです。

echo "Test 3\n";
foreach ($array as $key=>$value) {
    if ((string)$key == '') { // Cast back to string - fixes problem
        echo "$value\n";
    }
}
echo "Test 4\n";
foreach ($array as $key=>$value) {
    if ((string)$key === '0') { // Cast back to string - fixes problem
        echo "$value\n";
    }
}

1
これは実際には質問に対する答えではありません。
Flimm

0

@davidソリューションについては、連想配列の文字列値にアクセスしようとすると、数値が機能しないことに注意してください。私の推測では、(配列にアクセスするときに)背後で整数にキャストされ、値が見つかりません。整数として値にアクセスすることもできません。しかし、array_shift()を使用して値を取得したり、配列を反復したりできます。

$data = new stdClass;
$data->{"0"} = "Zero";
$data->{"1"} = "One";
$data->{"A"} = "A";
$data->{"B"} = "B";

$data = (array)$data;

var_dump($data);
/*
Note the key "0" is correctly saved as a string:
array(3) {
  ["0"]=>
  string(4) "Zero"
  ["A"]=>
  string(1) "A"
  ["B"]=>
  string(1) "B"
}
*/

//Now let's access the associative array via the values 
//given from var_dump() above:
var_dump($data["0"]); // NULL -> Expected string(1) "0"
var_dump($data[0]); // NULL (as expected)
var_dump($data["1"]); // NULL -> Expected string(1) "1"
var_dump($data[1]); // NULL (as expected)
var_dump($data["A"]); // string(1) "A" (as expected)
var_dump($data["B"]); // string(1) "B" (as expected)

どのphpバージョンですか?私はあなたの例を正確に試しました、そしてキー"0"0phpでなり7.2.10ます。
J.BizMai

-1

並べ替えキーを16進数のsha1にする必要がある配列を並べ替えようとしたときに、この問題が発生しました。結果のsha1値に文字がない場合、PHPはキーを整数に変換します。しかし、文字列の相対的な順序で配列をソートする必要がありました。したがって、並べ替え順序を変更せずにキーを文字列にする方法を見つける必要がありました。

ASCIIチャート(https://en.wikipedia.org/wiki/ASCII)を見ると、感嘆符はスペースとほぼ同じようにソートされ、すべての数字と文字よりも確実に低くなっています。

そこで、キー文字列の最後に感嘆符を追加しました。

for(...) {

    $database[$sha.'!'] = array($sha,$name,$age);
}

ksort($database);
$row = reset($database);
$topsha = $row[0];

それでは、整数に変換しないと、「123」のような数値文字列をPHP配列のキーとして使用することは不可能だと言っているのでしょうか。
Flimm

いいえ-ksort()を使用して配列をソートするときに、すべての数値であるキーを整数として扱うだけです-整数に変換されることはありません-ソート中に1つとして比較されるだけです。
drchuck
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.