Ciąg liczbowy jako klucz tablicy w PHP

104

Czy możliwe jest użycie ciągu liczbowego, takiego "123"jak klucz w tablicy PHP, bez konwersji na liczbę całkowitą?

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

wydruki

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

chcę

array(1) {
  ["123"]=>
  int(1)
}
Dogbert
źródło
7
Ponieważ PHP jest napisane luźno, "123"== 123do prawie każdego celu. Jaki jest powód, dla którego chcesz, aby był konkretnie jako ciąg (a posiadanie int jest złe)?
ircmaxell
17
Przyczyna, która przychodzi mi na myśl, odnosi się do funkcji tablicowych, takich jak array_merge „Jeśli tablice wejściowe mają te same klucze łańcuchowe, późniejsza wartość dla tego klucza zastąpi poprzednią. Jeśli jednak tablice zawierają klucze numeryczne , późniejsza wartość nie będzie nadpisze oryginalną wartość, ale zostanie dodana. "
ficuscr
8
Inny przykład, w którym ciągi numeryczne jako klucze tablic są problematyczne:asort
swenedo
4
Inny przypadek użycia: przejście danych JSON w testach jednostkowych. Konwersja takiej tablicy na JSON iz powrotem nie pozwoli ci stwierdzić, że oryginał i wynik są dokładnie takie same.
David

Odpowiedzi:

90

Nie; nie, nie jest:

Z instrukcji :

Klucz może być liczbą całkowitą lub łańcuchem. Jeśli klucz jest standardową reprezentacją liczby całkowitej, zostanie zinterpretowany jako taki (tj. „8” będzie interpretowane jako 8, a „08” będzie interpretowane jako „08”).

Uzupełnienie

Z powodu poniższych komentarzy pomyślałem, że fajnie byłoby wskazać, że zachowanie jest podobne, ale nie identyczne, jak klucze obiektów JavaScript.

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

foo['10']; // "bar"
foo[10]; // "bar"
foo[012]; // "bar"
foo['012']; // undefined!
Hamish
źródło
107
PHP, IE po stronie serwera.
Marek Maurizio
5
Wygląda na to, że jest sposób! Czy nie zgadzasz się z tą odpowiedzią? stackoverflow.com/a/35180513/247696
Flimm
1
Jak?! .. foo [012] return "bar"
Himanshu
2
@Himanshu: ponieważ php interpretuje liczby zaczynające się od 0 jako ósemkowe. więc 012 to ósemkowe 10.
Yeasir Arafat Majumder
49

Tak, jest to możliwe poprzez rzutowanie stdClassobiektu na tablicę :

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

To daje (do wersji PHP 7.1):

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

(Aktualizacja: Moja pierwotna odpowiedź pokazała bardziej skomplikowany sposób przy użyciu, json_decode()a json_encode()który nie jest konieczny.)

Zwróć uwagę na komentarz : niestety nie jest możliwe bezpośrednie odwołanie się do wartości: $data['12']spowoduje to powiadomienie.

Aktualizacja :
Od PHP 7.2 jest również możliwe użycie ciągu liczbowego jako klucza do odniesienia do wartości:

var_dump( $data['12'] ); // int 32
David
źródło
2
Jednak bezpośredni dostęp do wartości za pomocą klucza łańcuchowego nie działa. Dodaj tę linię do np echo $data['12'];. Wyświetli błąd „Uwaga: Niezdefiniowane przesunięcie: 12 w - w linii 5”.
LS
Tak, masz rację. Zakładając, że czasami było to możliwe w przeszłości.
David
1
kiedy użyjesz laravel dd ($ data) to się zawiesi: P
Kamil Kiełczewski
2
W PHP 7.2.0RC2 zachowanie jest takie samo jak poprzednio.
dev0
1
Najwyraźniej array_key_existsnie znajdzie go też w starszych wersjach.
Don't Panic
12

Jeśli potrzebujesz użyć klucza numerycznego w strukturze danych php, obiekt będzie działał. A obiekty zachowują porządek, więc możesz iterować.

$obj = new stdClass();
$key = '3';
$obj->$key = 'abc';
steampowered
źródło
To bardzo dobra sugestia. Piszę kod framework i mam do czynienia z kimś, kto przekazuje tablicę, która może mieć „przypadkowe” indeksowanie: tablicę („to”, „tamto”) lub indeksowanie „asocjacyjne”: tablica (123 => tablica („ta”, „ta”) ')). Teraz dzięki tobie mogę po prostu wpisać wskazówkę;) +1
Just Plain High
Ale czy można użyć ciągu liczbowego, takiego jak „123”, jako klucza w tablicy PHP, bez przekształcania go w liczbę całkowitą?
Flimm
@Flimm nie, to nie jest możliwe, dlatego proponuję swoje rozwiązanie.
steampowered
@Flimm, ta odpowiedź wydaje się być sprzeczna z instrukcją PHP : ciągi zawierające prawidłowe liczby całkowite będą rzutowane na typ całkowity. Np. Klucz „8” będzie faktycznie przechowywany pod 8. Z drugiej strony „08” nie będzie rzutowane, ponieważ nie jest prawidłową liczbą dziesiętną. , chociaż nie przetestowałem jego odpowiedzi.
steampowered
To zdanie znajduje się w sekcji „Określanie za pomocą” array(), więc zakładam, że w tym kontekście ciągi określające prawidłowe liczby całkowite będą rzutowane na typ całkowity. Okazuje się jednak, że istnieją inne sposoby tworzenia tablic, gdzie tak się nie dzieje, takie jak odpowiedź Davida, którą przetestowałem
Flimm
10

Moje obejście to:

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

Znak spacji (przedrostek) jest dobrym rozwiązaniem, ponieważ zachowaj konwersję int:

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

Zobaczysz 55 jako int.

Undolog
źródło
4
Lub "0$id" => $value. Prepping z 0pracami też.
nawfal
Więc mówisz, że nie jest możliwe użycie ciągu liczbowego, takiego jak „123”, jako klucza w tablicy PHP, bez konwersji na liczbę całkowitą?
Flimm
5

Możesz przerzucić klucz do łańcucha, ale ostatecznie zostanie on przekonwertowany na liczbę całkowitą z powodu luźnego pisania w PHP. Sam zobacz:

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

Z podręcznika PHP:

Klucz może być liczbą całkowitą lub łańcuchem. Jeśli klucz jest standardową reprezentacją liczby całkowitej, zostanie zinterpretowany jako taki (tj. „8” będzie interpretowane jako 8, a „08” będzie interpretowane jako „08”). Liczba zmiennoprzecinkowa w kluczu jest obcinana do liczby całkowitej. Typy tablic indeksowanych i asocjacyjnych są tego samego typu w PHP, które mogą zawierać zarówno indeksy całkowite, jak i łańcuchowe.

bcosca
źródło
1
Konwersja nie jest spowodowana luźnym pisaniem; php określa, czy łańcuch wygląda na numeryczny, a następnie konwertuje go.
Ja͢ck
1
Więc mówisz, że to niemożliwe? Ta odpowiedź pokazuje, że istnieje sposób na użycie łańcucha, który wygląda jak liczba całkowita, jako klucza w tablicy.
Flimm
IMHO problemem jest interpreter PHP. Nie można sobie nawet wyobrazić języka, który łączy łańcuchy i liczby całkowite jako klucze tablic. Najlepszym rozwiązaniem? Zgodnie z propozycją Undolog stackoverflow.com/a/15413637/1977778 najlepszym rozwiązaniem jest użycie spacji końcowej ... Niestety.
sentenza
@sentenza: Można to sobie wyobrazić, zwłaszcza że PHP pozwala na połączenie ciągów znaków i liczb całkowitych jako kluczy tablicy:[42 => 'answer', 'snafu' => 'fubar']
LS
@LS tak. Wiem, że PHP pozwala na to, ale jeśli weźmiesz pod uwagę klucze w hipotetycznym systemie typów ogólnych, nie będą one pasować do żadnego typu mieszanego, który obejmuje ciągi i liczby w tym samym czasie. Luźne wpisywanie stosowane do kluczy tablicy asocjacyjnej jest po prostu podatne na błędy.
sentenza
1

Miałem ten problem, próbując scalić tablice, które miały zarówno klucze łańcuchowe, jak i całkowite. Ważne było, aby liczby całkowite były również traktowane jako ciągi znaków, ponieważ były to nazwy pól wejściowych (np. Rozmiary butów itp.)

Kiedy używałem $data = array_merge($data, $extra);PHP, „zmieniałem kolejność” kluczy. Podczas próby uporządkowania, klucze liczb całkowitych (próbowałem z 6- '6'- "6"nawet (string)"6"jako klucze) zostały przemianowane z 0 na n... Jeśli się nad tym zastanowić, w większości przypadków byłoby to pożądane zachowanie.

Możesz obejść ten problem, używając $data = $data + $extra;zamiast tego. Całkiem proste, ale na początku o tym nie pomyślałem ^^.

Brainfeeder
źródło
Dokładnie ten sam problem doprowadził mnie do tej strony, ale muszę powiedzieć, że nie jest to odpowiedź na pytanie OP.
Flimm
@Flimm True. Ale poszukiwanie odpowiedzi doprowadziło mnie do tej strony. Pomyślałem moje rozwiązanie może być pomocne dla innych Googlersami :)
Brainfeeder
1

Ciągi zawierające prawidłowe liczby całkowite będą rzutowane na typ całkowity. Np. Klucz „8” będzie faktycznie przechowywany pod 8. Z drugiej strony „08” nie będzie rzutowane, ponieważ nie jest prawidłową liczbą dziesiętną.

ŹLE

Mam funkcję rzutowania, która obsługuje rzutowanie sekwencyjne do tablic asocjacyjnych,

$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
}
TarranJones
źródło
1

Aby obejść ten problem, możesz zakodować tablicę PHP do obiektu json za pomocą opcji JSON_FORCE_OBJECT.

tj. ten przykład:

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

spowoduje:

     RESULT: {"0" : "foo", "1": "bar", "2" : "baz"}
GigiManco
źródło
0

Napotkałem ten problem na tablicy z kluczami „0” i „”. Oznaczało to, że nie mogłem sprawdzić kluczy tablicy za pomocą == lub ===.

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

Sposób obejścia problemu polega na rzutowaniu kluczy tablic z powrotem na ciągi przed użyciem.

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";
    }
}
fisharebest
źródło
1
To nie jest tak naprawdę odpowiedź na pytanie.
Flimm
0

Jeśli chodzi o rozwiązanie @david, pamiętaj, że podczas próby uzyskania dostępu do wartości ciągu w tablicy asocjacyjnej liczby nie będą działać. Domyślam się, że są one rzutowane na liczby całkowite za kulisami (podczas uzyskiwania dostępu do tablicy) i nie znaleziono żadnej wartości. Dostęp do wartości jako liczb całkowitych również nie zadziała. Ale możesz użyć array_shift (), aby uzyskać wartości lub iterować tablicę.

$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)
Nico Schefer
źródło
Która wersja php? Wypróbowałem dokładnie twój przykład i kluczem "0"jest 0php 7.2.10.
J.BizMai,
-1

Miałem ten problem podczas próby sortowania tablicy, w której potrzebowałem klucza sortowania, aby był to hex sha1. Gdy wynikowa wartość sha1 nie zawiera liter, PHP zamienia klucz na liczbę całkowitą. Ale musiałem posortować tablicę według względnej kolejności ciągów. Musiałem więc znaleźć sposób, aby wymusić na kluczu ciąg bez zmiany kolejności sortowania.

Patrząc na wykres ASCII ( https://en.wikipedia.org/wiki/ASCII ), wykrzyknik jest mniej więcej taki sam jak spacja iz pewnością mniejszy niż wszystkie cyfry i litery.

Więc dodałem wykrzyknik na końcu ciągu klucza.

for(...) {

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

ksort($database);
$row = reset($database);
$topsha = $row[0];
drchuck
źródło
Więc mówisz, że nie jest możliwe użycie ciągu liczbowego, takiego jak "123", jako klucza w tablicy PHP, bez konwersji na liczbę całkowitą?
Flimm
Nie - podczas sortowania tablicy przy użyciu ksort () traktuje on tylko klucz, który jest wszystkimi liczbami, jako liczby całkowite - nigdy nie jest konwertowany na liczbę całkowitą - tylko porównywany jako jeden podczas sortowania.
drchuck