Một chuỗi số làm khóa mảng trong PHP


104

Có thể sử dụng một chuỗi số "123"như một khóa trong một mảng PHP mà không cần chuyển đổi thành số nguyên không?

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

bản in

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

tôi muốn

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

7
Vì PHP được gõ lỏng lẻo, nên "123"== 123cho hầu hết mọi mục đích. Lý do bạn muốn nó cụ thể là một chuỗi là gì (và có một int là không tốt)?
ircmaxell

17
Lý do mà tôi nghĩ đến liên quan đến các hàm mảng như array_merge "Nếu các mảng đầu vào có các khóa chuỗi giống nhau, thì giá trị sau của khóa đó sẽ ghi đè lên khóa trước đó. Tuy nhiên, nếu các mảng chứa khóa số thì giá trị sau đó sẽ không ghi đè giá trị ban đầu, nhưng sẽ được thêm vào. "
ficuscr

8
Một ví dụ nơi chuỗi số như phím mảng là có vấn đề:asort
swenedo


4
Một trường hợp sử dụng khác: thử nghiệm đơn vị chuyển đổi dữ liệu JSON. Việc chuyển đổi một mảng như vậy thành JSON và ngược lại sẽ không cho phép bạn khẳng định rằng cả hai, bản gốc và kết quả đều hoàn toàn giống nhau.
David

Câu trả lời:


90

Không; không, không phải:

Từ sách hướng dẫn :

Khóa có thể là một số nguyên hoặc một chuỗi. Nếu một khóa là đại diện tiêu chuẩn của một số nguyên, nó sẽ được hiểu như vậy (tức là "8" sẽ được hiểu là 8, trong khi "08" sẽ được hiểu là "08").

Phụ lục

Vì các nhận xét bên dưới, tôi nghĩ sẽ rất vui khi chỉ ra rằng hành vi tương tự nhưng không giống với các khóa đối tượng JavaScript.

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

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

107
PHP, IE phía máy chủ.
Marek Maurizio

5
Có vẻ như có một cách, thực sự! Bạn có không đồng ý với câu trả lời này? stackoverflow.com/a/35180513/247696
Flimm

1
Làm thế nào?! .. foo [012] return "bar"
Himanshu.

2
@Himanshu: vì php diễn giải các số bắt đầu bằng 0 là bát phân. do đó 012 là bát phân 10.
Yeasir Arafat Majumder

49

Có, có thể bằng cách ép kiểu mảng một stdClassđối tượng:

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

Điều đó mang lại cho bạn (lên đến phiên bản PHP 7.1):

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

(Cập nhật: Câu trả lời ban đầu của tôi cho thấy một cách phức tạp hơn bằng cách sử dụng json_decode()json_encode()không cần thiết.)

Lưu ý nhận xét : Rất tiếc là không thể tham chiếu trực tiếp giá trị: $data['12']sẽ dẫn đến thông báo.

Cập nhật :
Từ PHP 7.2 trở đi, nó cũng có thể sử dụng một chuỗi số làm khóa để tham chiếu giá trị:

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

2
Tuy nhiên, truy cập trực tiếp giá trị bằng khóa chuỗi không hoạt động. Thêm dòng này vào ví dụ của bạn: echo $data['12'];. Nó sẽ đưa ra lỗi, "Thông báo: Độ lệch không xác định: 12 in - trên dòng 5".
LS

1
khi U sử dụng laravel đ ($ data) nó sẽ sụp đổ: P
Kamil Kiełczewski

2
Trong PHP 7.2.0RC2, hành vi vẫn giống như trước.
dev0

1
Có vẻ như array_key_existssẽ không tìm thấy nó trong các phiên bản cũ hơn.
Đừng hoảng sợ

1
không hoạt động trong php 7.4
jasmines

12

Nếu bạn cần sử dụng phím số trong cấu trúc dữ liệu php, một đối tượng sẽ hoạt động. Và các đối tượng duy trì trật tự, vì vậy bạn có thể lặp lại.

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

Đây là một gợi ý rất tốt. Tôi đang viết mã khung và phải đối mặt với việc ai đó truyền một mảng có thể có lập chỉ mục "ngẫu nhiên": array ('this', 'that') hoặc "liên kết" lập chỉ mục: array (123 => array ('this', 'that ')). Bây giờ, nhờ có bạn, tôi có thể chỉ typehint;) 1
Just Plain cao

Nhưng liệu có thể sử dụng một chuỗi số như "123" làm khóa trong một mảng PHP mà nó không được chuyển đổi thành số nguyên không?
Flimm

@Flimm không, điều đó là không thể, đó là lý do tại sao tôi đưa ra giải pháp của mình.
steampowered

@Flimm câu trả lời đó dường như mâu thuẫn với hướng dẫn sử dụng PHP : Các chuỗi chứa số nguyên hợp lệ sẽ được chuyển sang kiểu số nguyên. Ví dụ: khóa "8" sẽ thực sự được lưu trữ dưới 8. Mặt khác, "08" sẽ không được ép kiểu, vì nó không phải là số nguyên thập phân hợp lệ. , mặc dù tôi chưa kiểm tra câu trả lời của anh ấy.
steampowered

Câu đó nằm trong phần "Chỉ định với array(), vì vậy tôi giả sử rằng trong ngữ cảnh đó, các chuỗi chỉ định số nguyên hợp lệ sẽ được chuyển thành kiểu số nguyên. Nhưng hóa ra có nhiều cách khác để tạo mảng, trong đó điều đó không xảy ra, chẳng hạn như trong câu trả lời của David, mà tôi đã thử nghiệm.
Flimm

10

Cách giải quyết của tôi là:

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

Ký tự khoảng trắng (thêm vào trước) là một giải pháp tốt vì giữ nguyên chuyển đổi int:

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

Bạn sẽ thấy 55 là int.


4
Hoặc "0$id" => $value. Thích thú với 0công việc quá.
nawfal

Vì vậy, bạn đang nói rằng không thể sử dụng một chuỗi số như "123" làm khóa trong một mảng PHP mà nó không được chuyển đổi thành một số nguyên?
Flimm

5

Bạn có thể nhập khóa thành một chuỗi nhưng cuối cùng nó sẽ được chuyển đổi thành một số nguyên do cách gõ lỏng lẻo của PHP. Hãy tự mình xem:

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

Từ hướng dẫn sử dụng PHP:

Khóa có thể là một số nguyên hoặc một chuỗi. Nếu một khóa là đại diện tiêu chuẩn của một số nguyên, nó sẽ được hiểu như vậy (tức là "8" sẽ được hiểu là 8, trong khi "08" sẽ được hiểu là "08"). Dấu nổi trong khóa được cắt ngắn thành số nguyên. Các kiểu mảng được lập chỉ mục và kết hợp là cùng một kiểu trong PHP, có thể chứa cả chỉ số nguyên và chuỗi.


1
Việc chuyển đổi không phải do đánh máy lỏng lẻo; php xác định xem chuỗi trông số và sau đó chuyển đổi nó.
Ja͢ck

1
Vậy bạn đang nói là không được à? Câu trả lời này cho thấy rằng có một cách để sử dụng một chuỗi trông giống như một số nguyên làm khóa trong một mảng.
Flimm

IMHO vấn đề là trình thông dịch PHP. Thậm chí không thể tưởng tượng có một ngôn ngữ kết hợp chuỗi và số nguyên dưới dạng các khóa mảng. Giải pháp tốt nhất? Theo đề xuất của Undolog stackoverflow.com/a/15413637/1977778 , giải pháp tốt nhất là sử dụng khoảng trắng ở cuối ... Thật đáng buồn.
sentenza

@sentenza: Đó có thể tưởng tượng, đặc biệt là kể từ PHP cho phép một hỗn hợp của các chuỗi và số nguyên như các phím của một mảng:[42 => 'answer', 'snafu' => 'fubar']
LS

@LS vâng. Tôi biết rằng PHP cho phép bạn làm như vậy, nhưng nếu bạn xem xét các khóa trong một hệ thống kiểu chung giả định, nó sẽ không khớp với bất kỳ kiểu hỗn hợp nào bao gồm các chuỗi và số cùng một lúc. Cách gõ lỏng lẻo được áp dụng cho các phím của một mảng kết hợp đơn giản là dễ xảy ra lỗi.
sentenza,

1

Tôi đã gặp sự cố này khi cố gắng hợp nhất các mảng có cả khóa chuỗi và khóa số nguyên. Điều quan trọng là các số nguyên cũng sẽ được xử lý dưới dạng chuỗi vì đây là tên cho các trường đầu vào (như kích thước giày, v.v.)

Khi tôi sử dụng $data = array_merge($data, $extra);PHP sẽ 'sắp xếp lại' các khóa. Trong một nỗ lực thực hiện thứ tự, các khóa số nguyên (tôi đã thử với 6- '6'- "6"thậm chí (string)"6"là khóa) đã được đổi tên từ 0 thànhn ... Nếu bạn nghĩ về nó, trong hầu hết các trường hợp, đây sẽ là hành vi mong muốn.

Bạn có thể giải quyết vấn đề này bằng cách sử dụng $data = $data + $extra;thay thế. Khá thẳng thắn, nhưng tôi không nghĩ ra nó lúc đầu ^^.


Cùng một vấn đề chính xác đã dẫn tôi đến trang này, nhưng tôi phải nói rằng đây không phải là câu trả lời cho câu hỏi của OP.
Flimm

@Flimm Đúng. Nhưng tìm kiếm câu trả lời đã dẫn tôi đến trang này. Tôi đã tìm giải pháp của tôi có thể là một trợ giúp cho nhân viên của Google khác :)
Brainfeeder

1

Các chuỗi chứa các số nguyên hợp lệ sẽ được chuyển sang kiểu số nguyên. Ví dụ: khóa "8" sẽ thực sự được lưu trữ dưới 8. Mặt khác, "08" sẽ không được ép kiểu, vì nó không phải là số nguyên thập phân hợp lệ.

SAI LẦM

Tôi có một chức năng truyền xử lý truyền tuần tự đến truyền mảng liên kết,

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

không hoạt động trong php 7.4
jasmines

1

Như một giải pháp khác, bạn có thể mã hóa mảng PHP thành đối tượng json, với tùy chọn JSON_FORCE_OBJECT.

tức là, Ví dụ này:

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

sẽ cho kết quả:

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

0

Tôi đã gặp sự cố này trên một mảng có cả '0' và '' làm khóa. Điều đó có nghĩa là tôi không thể kiểm tra các khóa mảng của mình bằng == hoặc ===.

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

Cách giải quyết là chuyển các phím mảng trở lại chuỗi trước khi sử dụng.

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
Đây không thực sự là một câu trả lời cho câu hỏi.
Flimm

0

Về giải pháp @david, xin lưu ý rằng khi bạn cố gắng truy cập các giá trị chuỗi trong mảng liên kết, các số sẽ không hoạt động. Dự đoán của tôi là chúng được chuyển thành các số nguyên phía sau (khi truy cập vào mảng) và không tìm thấy giá trị nào. Việc truy cập các giá trị dưới dạng số nguyên cũng sẽ không hoạt động. Nhưng bạn có thể sử dụng array_shift () để lấy các giá trị hoặc lặp lại mảng.

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

Phiên bản php nào? Tôi đã thử chính xác ví dụ của bạn và khóa "0"trở thành 0với php 7.2.10.
J.BizMai

-1

Tôi đã gặp sự cố này khi cố gắng sắp xếp một mảng mà tôi cần khóa sắp xếp là một hex sha1. Khi giá trị sha1 kết quả không có chữ cái nào, PHP sẽ biến khóa thành số nguyên. Nhưng tôi cần sắp xếp mảng theo thứ tự tương đối của các chuỗi. Vì vậy, tôi cần tìm cách buộc khóa thành một chuỗi mà không thay đổi thứ tự sắp xếp.

Nhìn vào biểu đồ ASCII ( https://en.wikipedia.org/wiki/ASCII ), dấu chấm than sắp xếp giống như khoảng trắng và chắc chắn thấp hơn tất cả các số và chữ cái.

Vì vậy, tôi đã thêm một dấu chấm than vào cuối chuỗi khóa.

for(...) {

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

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

Vì vậy, bạn đang nói rằng không thể sử dụng một chuỗi số như "123" làm khóa trong một mảng PHP mà không được chuyển đổi thành số nguyên?
Flimm

Không - nó chỉ coi khóa là tất cả các số dưới dạng số nguyên khi sắp xếp mảng bằng ksort () - nó không bao giờ được chuyển đổi thành số nguyên - chỉ được so sánh như một trong khi sắp xếp.
drchuck
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.