PHP'de dizi anahtarı olarak sayısal bir dize


104

"123"Tam sayıya dönüştürülmeden, bir PHP dizisindeki anahtar gibi sayısal bir dizge kullanmak mümkün müdür ?

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

baskılar

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

İstiyorum

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

7
PHP gevşek bir şekilde yazıldığından, hemen hemen her amaç için "123"== 123. Bunu özellikle bir dizge olarak istemenizin nedeni nedir (ve bir int sahip olmak kötüdür)?
ircmaxell

17
Aklıma gelen neden, array_merge "Girdi dizileri aynı dizge anahtarlarına sahipse, o anahtar için sonraki değer öncekinin üzerine yazılır. Ancak diziler sayısal anahtarlar içeriyorsa , sonraki değer orijinal değerin üzerine yazın, ancak eklenecektir. "
ficuscr

8
Dizi anahtarları olarak sayısal dizelerin sorunlu olduğu başka bir örnek:asort
swenedo


4
Başka bir kullanım örneği: JSON veri geçişinin birim testi. Böyle bir diziyi JSON'a ve geri dönüştürmek, hem orijinalin hem de sonucun tamamen aynı olduğunu iddia etmenize izin vermez.
David

Yanıtlar:


90

Hayır; hayır değil:

Gönderen manuel :

Bir anahtar, bir tamsayı veya bir dize olabilir. Bir anahtar, bir tamsayının standart temsiliyse, bu şekilde yorumlanacaktır (yani "8", 8 olarak yorumlanacak ve "08", "08" olarak yorumlanacaktır).

Ek

Aşağıdaki yorumlar nedeniyle, davranışın JavaScript nesne anahtarlarına benzer ancak aynı olmadığını belirtmenin eğlenceli olacağını düşündüm .

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

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

107
PHP, sunucu tarafı IE.
Marek Maurizio

5
Aslında bir yolu var gibi görünüyor! Bu cevaba katılmıyor musunuz? stackoverflow.com/a/35180513/247696
Flimm

1
Nasıl?! .. foo [012] "bar" a dönüş
Himanshu

2
@Himanshu: çünkü php, 0 ile başlayan sayıları sekizlik olarak yorumlar. yani 012 sekizlik 10'dur.
Yeasir Arafat Majumder

49

Evet, bir stdClassnesneyi dizi halinde çevirmek mümkündür :

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

Bu size (PHP 7.1 sürümüne kadar) şunları sağlar:

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

(Güncelleme: Orijinal cevabım kullanarak json_decode()ve json_encode()gerekli olmayan daha karmaşık bir yol gösterdi .)

Yoruma dikkat edin : Maalesef değere doğrudan atıfta bulunmak mümkün değildir: $data['12']bir bildirimle sonuçlanacaktır.

Güncelleme :
PHP 7.2'den itibaren, değere başvurmak için anahtar olarak sayısal bir dizge kullanmak da mümkündür:

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

2
Yine de, bir dize anahtarıyla değere doğrudan erişim çalışmaz. Senin örneğe bu satırı ekleyin: echo $data['12'];. "Not: Undefined offset: 12 in - on line 5" hatasını verecektir.
LS

Evet haklısın. Geçmişte bazen mümkün olduğunu varsayarsak.
David

1
U laravel dd ($ data) kullandığında çökecek: P
Kamil Kiełczewski

2
PHP 7.2.0RC2'de davranış öncekiyle aynıdır.
dev0

1
Görünüşe göre array_key_existseski sürümlerde de bulamayacak.
Panik yapmayın

12

Bir php veri yapısında sayısal bir anahtar kullanmanız gerekirse, bir nesne çalışacaktır. Ve nesneler düzeni korur, böylece yineleme yapabilirsiniz.

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

Bu çok güzel bir öneri. Çerçeve kodu yazıyorum ve "kazara" indeksleme: dizi ('bu', 'o') veya "ilişkilendirilebilir" dizinleme: dizi (123 => dizi ('bu', 'o ')). Şimdi, senin sayende sadece yazabilirim;) +1
Just Plain High

Fakat bir tamsayıya dönüştürülmeden bir PHP dizisinde anahtar olarak "123" gibi sayısal bir dizge kullanmak mümkün müdür?
Flimm

@Flimm hayır bu mümkün değil, bu yüzden çözümümü sunuyorum.
steampowered

@Flimm cevabı PHP kılavuzuyla çelişiyor gibi görünüyor : Geçerli tamsayılar içeren dizeler tamsayı türüne dönüştürülecek. Örneğin, "8" anahtarı aslında 8'in altında saklanacaktır. Öte yandan, "08" geçerli bir ondalık tamsayı olmadığı için dönüştürülmeyecektir. cevabını test etmemiş olmama rağmen.
steampowered

Bu cümle "ile belirtme bölümünün altında array(), bu nedenle bu bağlamda geçerli tamsayıları belirten dizelerin tamsayı türüne dönüştürüleceğini varsayıyorum . Ancak dizi oluşturmanın başka yolları da var, bunun olmadığı yerde, David'in cevabında olduğu gibi, test ettiğim.
Flimm

10

Çözümüm:

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

Uzay karakteri (başa eklenen) iyi bir çözümdür çünkü int dönüşümünü koruyun:

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

55'i int olarak göreceksiniz.


4
Veya "0$id" => $value. Eserler için 0de ön ödeme .
nawfal

Yani tam sayıya dönüştürülmeden bir PHP dizisinde anahtar olarak "123" gibi sayısal bir dizenin kullanılmasının mümkün olmadığını mı söylüyorsunuz?
Flimm

5

Anahtarı bir dizeye yazabilirsiniz, ancak PHP'nin gevşek yazması nedeniyle sonunda bir tam sayıya dönüştürülecektir. Kendin için gör:

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

PHP kılavuzundan:

Bir anahtar, bir tamsayı veya bir dize olabilir. Bir anahtar, bir tamsayının standart temsiliyse, bu şekilde yorumlanacaktır (yani, "8", 8 olarak yorumlanacak ve "08", "08" olarak yorumlanacaktır). Anahtardaki kayan sayılar tamsayıya kesilir. Dizine alınmış ve ilişkilendirilebilir dizi türleri PHP'de aynı türdendir ve hem tamsayı hem de dize dizinleri içerebilir.


1
Dönüşüm gevşek yazmadan kaynaklanmamaktadır; php, dizenin sayısal görünüp görünmediğini belirler ve sonra onu dönüştürür.
Jack

1
Yani bunun mümkün olmadığını mı söylüyorsun? Bu cevap , tamsayı gibi görünen bir dizeyi dizide anahtar olarak kullanmanın bir yolu olduğunu gösterir.
Flimm

IMHO sorun PHP yorumlayıcısıdır. Dizeleri ve tam sayıları dizi anahtarları olarak karıştıran bir dile sahip olmayı hayal etmek bile mümkün değildir. En iyi çözüm? Undolog stackoverflow.com/a/15413637/1977778 tarafından önerildiği gibi en iyi çözüm, takip eden bir boşluk kullanmaktır ... Ne yazık ki.
sentenza

@sentenza: O olduğu PHP bir dizinin anahtarları olarak dizeleri ve tamsayılar bir karışımını verir, özellikle de hayal etmek mümkün:[42 => 'answer', 'snafu' => 'fubar']
LS

@LS evet. PHP'nin bunu yapmanıza izin verdiğini biliyorum, ancak varsayımsal bir jenerik tür sistemindeki anahtarları düşünürseniz, dizeleri ve sayıları aynı anda kucaklayan herhangi bir karma türle eşleşmeyecektir . Gevşek yazarak bir ilişkisel dizinin şifreler uygulanan basit bir hata eğilimli.
sentenza

1

Hem string hem de tamsayı anahtarlarına sahip dizileri birleştirmeye çalışırken bu problemi yaşadım. Tam sayıların da dize olarak ele alınması önemliydi çünkü bunlar giriş alanları için isimlerdi (ayakkabı bedenlerinde vb. Gibi)

$data = array_merge($data, $extra);PHP'yi kullandığımda anahtarları 'yeniden sıralar'. Sıralamayı yaparken, tamsayı anahtarları ( 6- '6'- anahtarlarla "6"bile denedim (string)"6") 0'dan n... olarak yeniden adlandırıldı ... Eğer düşünürseniz, çoğu durumda istenen davranış bu olurdu.

Bunun $data = $data + $extra;yerine kullanarak bu sorunu çözebilirsiniz . Oldukça yalındır, ama ilk başta bunu düşünmemiştim ^^.


Aynı sorun beni bu sayfaya götürdü, ancak bunun OP'nin sorusuna cevap olmadığını söylemeliyim.
Flimm

@Flimm True. Ama bir cevap aramak beni bu sayfaya yönlendirdi. Çözümümün diğer Google çalışanları için yardımcı olabileceğini düşündüm :)
Brainfeeder

1

Geçerli tamsayılar içeren dizeler tamsayı türüne dönüştürülecektir. Örneğin, "8" anahtarı aslında 8'in altında saklanacaktır. Öte yandan, "08" geçerli bir ondalık tam sayı olmadığı için dönüştürülmeyecektir.

YANLIŞ

İlişkisel dizi çevrimini sıralı olarak işleyen bir çevrim işlevim var,

$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
}

1

Çözüm olarak, JSON_FORCE_OBJECT seçeneği ile PHP dizisini json nesnesine kodlayabilirsiniz.

yani, Bu örnek:

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

sonuçlanacak:

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

0

Anahtar olarak hem '0' hem de '' olan bir dizide bu problemle karşılaştım. Bu, dizi anahtarlarımı == veya === ile kontrol edemediğim anlamına geliyordu.

$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";
    }
}

Çözüm, kullanmadan önce dizi anahtarlarını dizelere geri döndürmektir.

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
Bu gerçekten sorunun cevabı değil.
Flimm

0

@David çözümüyle ilgili olarak, ilişkilendirilebilir dizideki dize değerlerine erişmeye çalıştığınızda, sayıların çalışmayacağını lütfen unutmayın. Tahminim, sahne arkasındaki tam sayılara dönüştürülürler (diziye erişirken) ve hiçbir değer bulunmaz. Değerlere tamsayı olarak erişmek de işe yaramayacaktır. Ancak, değerleri almak veya diziyi yinelemek için array_shift () kullanabilirsiniz.

$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)

Hangi php sürümü? Tam olarak örneğinizi denedim ve anahtar php ile "0"olur . 07.2.10
J.BizMai

-1

Sıralama anahtarının onaltılık sha1 olmasını istediğim bir diziyi sıralamaya çalışırken bu sorunu yaşadım. Sonuçta ortaya çıkan sha1 değerinde harf yoksa, PHP anahtarı bir tam sayıya dönüştürür. Ancak diziyi dizelerin göreceli sırasına göre sıralamam gerekiyordu. Bu yüzden, sıralama düzenini değiştirmeden anahtarı bir dizge olmaya zorlamanın bir yolunu bulmam gerekiyordu.

ASCII grafiğine ( https://en.wikipedia.org/wiki/ASCII ) bakıldığında, ünlem işareti boşlukla hemen hemen aynıdır ve kesinlikle tüm sayılardan ve harflerden daha düşüktür.

Bu yüzden anahtar dizesinin sonuna bir ünlem işareti ekledim.

for(...) {

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

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

Öyleyse, bir tam sayıya dönüştürülmeden bir PHP dizisinde anahtar olarak "123" gibi sayısal bir dizenin kullanılmasının mümkün olmadığını mı söylüyorsunuz?
Flimm

Hayır - diziyi ksort () kullanarak sıralarken yalnızca tüm sayılardan oluşan anahtara bir tamsayı olarak davranır - asla bir tam sayıya dönüştürülmez - sadece sıralama sırasında bir ile karşılaştırıldığında.
drchuck
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.