Bagaimana cara mengakses properti objek dengan nama seperti integer?

87

Saya menggunakan json_decode()sesuatu seperti:

$myVar = json_decode($data)

Yang memberi saya keluaran seperti ini:

[highlighting] => stdClass Object
        (
            [448364] => stdClass Object
                (
                    [Data] => Array
                        (
                            [0] => Tax amount liability is ....... 

Saya ingin mengakses nilai string di kunci [0]. Ketika saya mencoba melakukan sesuatu seperti:

print $myVar->highlighting->448364->Data->0;

Saya mendapatkan kesalahan ini:

Kesalahan Parse: kesalahan sintaks, T_DNUMBER tidak terduga

Dua angka / bilangan bulat tampaknya ada masalah.

avinash shah
sumber
1
@FelixKling: Saya juga membuat CV, tapi ternyata itu bukan penipuan: ada bedanya jika nama properti dimulai dengan angka atau semua angka !
Jon
@Jon: Mmmh, menarik ... seharusnya melakukan tes sebelum saya kira. Terima kasih telah memberi tahu saya!
Felix Kling

Jawaban:

288

Diperbarui untuk PHP 7.2

PHP 7.2 memperkenalkan perubahan perilaku untuk mengubah kunci numerik dalam cast objek dan array , yang memperbaiki inkonsistensi khusus ini dan membuat semua contoh berikut berperilaku seperti yang diharapkan.

Satu hal lagi yang perlu dibingungkan!


Jawaban asli (berlaku untuk versi sebelum 7.2.0)

PHP memiliki bagiannya dalam lorong-lorong gelap yang Anda benar - benar tidak ingin berada di dalamnya. Properti objek dengan nama yang berupa angka adalah salah satunya ...

Apa yang mereka tidak pernah katakan padamu

Fakta # 1: Anda tidak dapat mengakses properti dengan nama yang bukan nama variabel legal dengan mudah

$a = array('123' => '123', '123foo' => '123foo');
$o = (object)$a;
echo $o->123foo; // error

Fakta # 2: Anda dapat mengakses properti tersebut dengan sintaks kurung kurawal

$a = array('123' => '123', '123foo' => '123foo');
$o = (object)$a;
echo $o->{'123foo'}; // OK!

Fakta # 3: Tetapi tidak jika nama properti adalah semua angka!

$a = array('123' => '123', '123foo' => '123foo');
$o = (object)$a;
echo $o->{'123foo'}; // OK!
echo $o->{'123'}; // error!

Contoh langsung .

Fakta # 4: Kecuali jika objek tersebut tidak berasal dari larik.

$a = array('123' => '123');
$o1 = (object)$a;
$o2 = new stdClass;
$o2->{'123'} = '123'; // setting property is OK

echo $o1->{'123'}; // error!
echo $o2->{'123'}; // works... WTF?

Contoh langsung .

Cukup intuitif, bukankah Anda setuju?

Apa yang dapat Anda lakukan

Opsi # 1: lakukan secara manual

Pendekatan paling praktis adalah dengan mentransmisikan kembali objek yang Anda minati ke dalam array, yang memungkinkan Anda mengakses properti:

$a = array('123' => '123', '123foo' => '123foo');
$o = (object)$a;
$a = (array)$o;
echo $o->{'123'}; // error!
echo $a['123']; // OK!

Sayangnya, ini tidak berfungsi secara rekursif. Jadi dalam kasus Anda, Anda perlu melakukan sesuatu seperti:

$highlighting = (array)$myVar->highlighting;
$data = (array)$highlighting['448364']->Data;
$value = $data['0']; // at last!

Opsi # 2: opsi nuklir

Pendekatan alternatifnya adalah menulis fungsi yang mengonversi objek menjadi array secara rekursif:

function recursive_cast_to_array($o) {
    $a = (array)$o;
    foreach ($a as &$value) {
        if (is_object($value)) {
            $value = recursive_cast_to_array($value);
        }
    }

    return $a;
}

$arr = recursive_cast_to_array($myVar);
$value = $arr['highlighting']['448364']['Data']['0'];

Namun, saya tidak yakin bahwa ini adalah pilihan yang lebih baik secara keseluruhan karena ini akan membuang semua properti yang tidak Anda minati dan juga yang Anda minati.

Opsi # 3: Memainkannya dengan Cerdas

Alternatif dari opsi sebelumnya adalah menggunakan fungsi JSON bawaan:

$arr = json_decode(json_encode($myVar), true);
$value = $arr['highlighting']['448364']['Data']['0'];

Fungsi JSON membantu melakukan konversi rekursif ke array tanpa perlu menentukan fungsi eksternal apa pun. Betapa pun diinginkannya tampilannya, ia memiliki kelemahan "nuke" dari opsi # 2 dan juga kerugiannya bahwa jika ada string di dalam objek Anda, string tersebut harus dikodekan dalam UTF-8 (ini adalah persyaratan json_encode).

Jon
sumber
Itu terjadi untuk menyelesaikan masalah saya juga! stackoverflow.com/questions/4643894/…
Bossliaw
Jon, terima kasih telah menyelamatkan saya. Masalah saya berbeda meskipun (saya kira itu benar-benar di bagian "apa yang mereka tidak pernah katakan"). Objek DateTime diambil dari DB tampaknya OK tetapi jika saya mengakses salah satu propertinya, seperti ->dateatau ->timezone, hanya nulldikembalikan. Saya perhatikan bahwa jika saya melakukan var_dumped objek sebelum menggunakan properti ini, nilai yang tepat akan dikembalikan. Kloning tidak memperbaikinya, jadi saya rasa itu benar-benar ada hubungannya dengan akses yang var_dumpmelakukan ... Lalu saya melihat Opsi # 1 dan voilá Anda, mengaksesnya sebagai array ( $objCastAsArray['date']) bekerja seperti pesona.
Armfoot
1
Fakta # 0 : Mentransmisikan array ke dalam objek seharusnya tidak menimbulkan bau yang tidak sedap. Fakta # 1 hingga Fakta # 3: tidak dibutuhkan.
Pacerier
4
@Pacerier: Saya setuju bahwa ini agak dipertanyakan, tetapi itu benar-benar masuk akal dalam beberapa situasi. Bagaimanapun, karena itu didokumentasikan di manual untuk bekerja seperti ini, pendapat pribadi kita tidak terlalu penting.
Jon
Alternatif untuk Opsi # 3 yang tidak memerlukan UTF-8 adalah$o = unserialize('O:8:"StdClass"' . substr(serialize($a),1));
OscarJ
10

Hanya ingin menambahkan penjelasan fasih Jon tentang alasan mengapa ini gagal. Itu semua karena ketika membuat sebuah array, php mengonversi kunci menjadi integer - jika bisa - yang menyebabkan masalah pencarian pada array yang telah dilemparkan ke objek, hanya karena kunci numerik dipertahankan. Ini bermasalah karena semua opsi akses properti mengharapkan atau diubah menjadi string. Anda dapat mengonfirmasi ini dengan melakukan hal berikut:

$arr = array('123' => 'abc');
$obj = (object) $arr;
$obj->{'123'} = 'abc';
print_r( $obj );

Yang akan menghasilkan:

stdClass Object ( 
  [123] => 'abc', 
  [123] => 'abc'
)

Jadi objek tersebut memiliki dua kunci properti, satu numerik (yang tidak dapat diakses) dan satu berbasis string. Inilah alasan mengapa Jon #Fact 4bekerja, karena dengan menyetel properti menggunakan kurung kurawal berarti Anda selalu mendefinisikan kunci berbasis string, bukan numerik.

Mengambil solusi Jon, tetapi memutarnya, Anda dapat menghasilkan objek dari array Anda yang selalu memiliki kunci berbasis string dengan melakukan hal berikut:

$obj = json_decode(json_encode($arr));

Mulai sekarang Anda dapat menggunakan salah satu dari yang berikut karena akses dengan cara ini selalu mengubah nilai di dalam kurung kurawal menjadi string:

$obj->{123};
$obj->{'123'};

PHP tidak logis tua yang bagus ...

Pebbl
sumber
1

Jika sebuah benda dimulai dengan @seperti:

SimpleXMLElement Object (
    [@attributes] => Array (
        [href] => qwertyuiop.html
        [id] => html21
        [media-type] => application/xhtml+xml
    )
)

Anda harus menggunakan:

print_r($parent_object->attributes());

karena $parent_object->{'@attributes'}atau $parent_object['@attributes']tidak akan berhasil.

Zydnar
sumber
3 tahun kemudian dan ini masih membantu orang, terima kasih! Meskipun jawaban Anda memperbaiki masalah saya, namun tidak ada penjelasannya. Adakah yang bisa menjelaskan alasan di balik ini?
Arbiter
1

Saya telah menyalin fungsi ini dari internet. Jika berfungsi seperti yang dikatakan ("Fungsi untuk Mengonversi Objek stdClass ke Array Multidimensi"), coba yang berikut ini:

<?php

    function objectToArray($d) {
        if (is_object($d)) {
            // Gets the properties of the given object
            // with get_object_vars function
            $d = get_object_vars($d);
        }

        if (is_array($d)) {
            /*
            * Return array converted to object
            * Using __FUNCTION__ (Magic constant)
            * for recursive call
            */
            return array_map(__FUNCTION__, $d);
        }
        else {
            // Return array
            return $d;
        }
    }

?>
  • pertama lewati array Anda untuk objectToArrayberfungsi
  • lalu ambil nilai kembali
  • gema [highlighting][448364][Data][0]

Sumber: PHP stdClass ke Array dan Array ke stdClass

Ruwantha
sumber
1

Alternatif terakhir untuk jawaban komprehensif Jon:

Cukup gunakan json_decode () dengan parameter kedua disetel ke true .

$array = json_decode($url, true);

Ini kemudian mengembalikan array asosiatif daripada objek jadi tidak perlu mengonversi setelah fakta.

Ini mungkin tidak cocok untuk setiap aplikasi tapi sangat membantu saya untuk dengan mudah mereferensikan properti dari objek oroginal.

Solusi ditemukan dalam tutorial ini - http://nitschinger.at/Handling-JSON-like-a-boss-in-PHP/

Salam

Bluekable
sumber
1

Untuk PHP 7

Mengakses properti Objek yang memiliki angka sebagai nama properti. Paling dibutuhkan setelah casting array ke objek.

    $arr = [2,3,7];
    $o = (object) $arr;

    $t = "1";
    $t2 = 1;
    $t3 = (1);

    echo $o->{1};      // 3
    echo $o->{'1'};   // 3
    echo $o->$t;        // 3
    echo $o->$t2;       // 3
    echo $o->$t3;       // 3

    echo $o->1;       // error
    echo $o->(1);      // error
umesh kadam
sumber
0

Saya khawatir Anda tidak diizinkan memberi nama objek yang dimulai dengan angka. Ubah nama yang pertama menjadi "448364" dimulai dengan huruf.

Yang kedua adalah array, yang harus diakses dengan tanda kurung seperti ini:

print myVar->highlighting->test_448364->Data[0]

sebagai gantinya

Gustav
sumber
Saya tidak bisa mengubahnya. Keluaran dikembalikan dari aplikasi yang tidak dapat saya kendalikan.
avinash shah