Uma string numérica como chave de array em PHP

104

É possível usar uma string numérica "123"como uma chave em um array PHP, sem ser convertido para um inteiro?

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

estampas

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

eu quero

array(1) {
  ["123"]=>
  int(1)
}
Dogbert
fonte
7
Como o PHP é digitado livremente, "123"== 123para quase todos os fins. Qual é a razão pela qual você deseja especificamente como uma string (e ter um int é ruim)?
ircmaxell
17
O motivo que me vem à mente está relacionado a funções de array como array_merge "Se os arrays de entrada tiverem as mesmas chaves de string, o último valor dessa chave substituirá o anterior. Se, no entanto, os arrays contiverem chaves numéricas , o último valor não sobrescreverá o valor original, mas será anexado. "
ficuscr
8
Outro exemplo em que strings numéricas como chaves de array é problemático:asort
swenedo
4
Outro caso de uso: teste de unidade de transição de dados JSON. Converter tal array em JSON e vice-versa não permitirá que você afirme que o original e o resultado são exatamente os mesmos.
David

Respostas:

90

Não; não, não é:

Do manual :

Uma chave pode ser um número inteiro ou uma string. Se uma chave for a representação padrão de um número inteiro, ela será interpretada como tal (ou seja, "8" será interpretado como 8, enquanto "08" será interpretado como "08").

Termo aditivo

Por causa dos comentários abaixo, achei que seria divertido apontar que o comportamento é semelhante, mas não idêntico, às chaves de objeto JavaScript.

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

foo['10']; // "bar"
foo[10]; // "bar"
foo[012]; // "bar"
foo['012']; // undefined!
Hamish
fonte
107
PHP, o IE do lado do servidor.
Marek Maurizio
5
Parece que há uma maneira, na verdade! Você discorda dessa resposta? stackoverflow.com/a/35180513/247696
Flimm
1
Como?! .. foo [012] return "bar"
Himanshu
2
@Himanshu: porque php interpreta números que começam com 0 como octais. então 012 é 10 octal.
Yeasir Arafat Majumder,
49

Sim, é possível lançando um array de um stdClassobjeto:

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

Isso dá a você (até a versão 7.1 do PHP):

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

(Atualização: minha resposta original mostrou uma maneira mais complicada de usar json_decode()e json_encode()que não é necessária.)

Observe o comentário : Infelizmente não é possível referenciar o valor diretamente: $data['12']resultará em um aviso.

Atualização :
A partir do PHP 7.2 também é possível usar uma string numérica como chave para referenciar o valor:

var_dump( $data['12'] ); // int 32
David
fonte
2
No entanto, o acesso direto ao valor com uma chave de string não funciona. Adicione esta linha ao seu exemplo: echo $data['12'];. Ele apresentará o erro "Aviso: Deslocamento indefinido: 12 pol - na linha 5".
LS
1
quando você usar laravel dd ($ data), ele
travará
2
No PHP 7.2.0RC2 o comportamento é o mesmo de antes.
dev0
1
Aparentemente, array_key_existstambém não o encontrará nas versões mais antigas.
Não entre em pânico
1
não funciona no php 7.4
jasmines
12

Se você precisar usar uma chave numérica em uma estrutura de dados php, um objeto funcionará. E os objetos preservam a ordem, para que você possa iterar.

$obj = new stdClass();
$key = '3';
$obj->$key = 'abc';
movido a vapor
fonte
Esta é uma sugestão muito boa. Estou escrevendo o código do framework e me deparei com alguém passando um array que pode ter indexação "acidental": array ('this', 'that') ou indexação "associativa": array (123 => array ('this', 'that ')). Agora, graças a você, posso apenas digitar uma dica;) +1
Just Plain High
Mas é possível usar uma string numérica como "123" como uma chave em um array PHP, sem ser convertido para um inteiro?
Flimm de
@Flimm não, isso não é possível, por isso apresento minha solução.
movido a vapor de
@Flimm essa resposta parece contradizer o manual do PHP : Strings contendo inteiros válidos serão convertidos para o tipo inteiro. Por exemplo, a chave "8" será armazenada em 8. Por outro lado, "08" não será convertido, pois não é um inteiro decimal válido. , embora eu não tenha testado sua resposta.
movido a vapor de
Essa frase está na seção "Especificando com array(), portanto, estou assumindo que , nesse contexto, as strings que especificam inteiros válidos serão convertidas para o tipo inteiro. Mas acontece que existem outras maneiras de criar matrizes, onde isso não acontece, como na resposta de David, que testei.
Flimm
10

Minha solução alternativa é:

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

O caractere de espaço (prefixar) é uma boa solução porque mantém a conversão int:

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

Você verá 55 como int.

Undolog
fonte
4
Ou "0$id" => $value. Pré-anexar com 0obras também.
nawfal
Então você está dizendo que não é possível usar uma string numérica como "123" como uma chave em um array PHP, sem ser convertido para um inteiro?
Flimm de
5

Você pode converter a chave em uma string, mas ela será eventualmente convertida em um inteiro devido à digitação livre do PHP. Veja por si mesmo:

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

Do manual do PHP:

Uma chave pode ser um número inteiro ou uma string. Se uma chave for a representação padrão de um número inteiro, ela será interpretada como tal (ou seja, "8" será interpretado como 8, enquanto "08" será interpretado como "08"). Os flutuadores na chave são truncados para um número inteiro. Os tipos de array indexado e associativo são do mesmo tipo em PHP, que podem conter índices inteiros e strings.

bcosca
fonte
1
A conversão não se deve a uma digitação solta; php determina se a string parece numérica e então a converte.
Ja͢ck,
1
Então você está dizendo que não é possível? Essa resposta mostra que há uma maneira de usar uma string que se parece com um inteiro como uma chave em um array.
Flimm de
IMHO o problema é o interpretador PHP. Nem é possível imaginar uma linguagem que mistura strings e inteiros como chaves de array. A melhor solução? Conforme proposto por Undolog stackoverflow.com/a/15413637/1977778, a melhor solução é usar um espaço à direita ... Infelizmente.
sentenza
@sentenza: Ele é possível imaginar, especialmente desde PHP permite uma mistura de strings e inteiros, como as chaves de um array:[42 => 'answer', 'snafu' => 'fubar']
LS
@LS sim. Eu sei que o PHP permite que você faça isso, mas se você considerar as chaves dentro de um sistema de tipo genérico hipotético, ele não corresponderá a nenhum tipo misto que abranja strings e números ao mesmo tempo. A digitação livre aplicada às teclas de uma matriz associativa é simplesmente propensa a erros.
sentenza
1

Eu tive esse problema ao tentar mesclar matrizes que tinham chaves de string e inteiras. Era importante que os inteiros também fossem tratados como string, uma vez que eram nomes para campos de entrada (como em tamanhos de sapato etc.)

Quando eu usava o $data = array_merge($data, $extra);PHP, eu 'reordenava' as chaves. Em uma tentativa de ordenar, as chaves inteiras (eu tentei com 6- '6'- "6"mesmo (string)"6"como chaves) foram renomeadas de 0 para n... Se você pensar bem, na maioria dos casos esse seria o comportamento desejado.

Você pode contornar isso usando $data = $data + $extra;. Bem direto, mas não pensei nisso no começo ^^.

Brainfeeder
fonte
Exatamente o mesmo problema me levou a esta página, mas devo dizer que esta não é a resposta à pergunta de OP.
Flimm de
@Flimm True. Mas a busca por uma resposta me levou a esta página. Achei que minha solução poderia ajudar outros Googlers :)
Brainfeeder
1

Strings contendo inteiros válidos serão convertidos para o tipo inteiro. Por exemplo, a chave "8" será armazenada em 8. Por outro lado, "08" não será convertido, pois não é um inteiro decimal válido.

ERRADO

Eu tenho uma função de casting que lida com o casting de array sequencial para associativo,

$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
fonte
não funciona no php 7.4
jasmines
1

Como solução alternativa, você pode codificar a matriz PHP em um objeto json, com a opção JSON_FORCE_OBJECT.

ou seja, este exemplo:

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

vai resultar em:

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

Corri para este problema em uma matriz com '0' e '' como chaves. Isso significava que eu não poderia verificar minhas chaves de array com == ou ===.

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

A solução alternativa é converter as chaves da matriz de volta nas strings antes de usar.

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
fonte
1
Esta não é realmente uma resposta à pergunta.
Flimm de
0

Com relação à solução @david, observe que quando você tenta acessar os valores da string na matriz associativa, os números não funcionam. Meu palpite é que eles são lançados em números inteiros nos bastidores (ao acessar a matriz) e nenhum valor é encontrado. Acessar os valores como inteiros também não funcionará. Mas você pode usar array_shift () para obter os valores ou iterar o array.

$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
fonte
Qual versão do php? Tentei exatamente o seu exemplo e a chave "0"passa 0a ser php 7.2.10.
J.BizMai
-1

Tive esse problema ao tentar classificar uma matriz em que precisava que a chave de classificação fosse um hex sha1. Quando um valor sha1 resultante não tem letras, o PHP transforma a chave em um inteiro. Mas eu precisava classificar a matriz na ordem relativa das strings. Então, eu precisava encontrar uma maneira de forçar a chave a ser uma string sem alterar a ordem de classificação.

Olhando para o gráfico ASCII ( https://en.wikipedia.org/wiki/ASCII ), o ponto de exclamação é classificado quase da mesma forma que o espaço e certamente menor do que todos os números e letras.

Então, acrescentei um ponto de exclamação no final da string chave.

for(...) {

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

ksort($database);
$row = reset($database);
$topsha = $row[0];
drchuck
fonte
Então você está dizendo que não é possível usar uma string numérica como "123" como uma chave em um array PHP, sem ser convertido em um inteiro?
Flimm de
Não - ele apenas trata a chave que contém todos os números como um inteiro ao classificar o array usando ksort () - ele nunca é convertido para um inteiro - apenas comparado como um durante a classificação.
drchuck de