Tamsayı gibi adlara sahip nesne özelliklerine nasıl erişilir?


87

Şöyle bir json_decode()şey kullanıyorum :

$myVar = json_decode($data)

Bu da bana şu şekilde çıktı veriyor:

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

[0] anahtarındaki dize değerine erişmek istiyorum. Şunun gibi bir şey yapmaya çalıştığımda:

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

Bu hatayı alıyorum:

Ayrıştırma hatası: sözdizimi hatası, beklenmeyen T_DNUMBER

İki sayı / tam sayı sorun gibi görünüyor.



1
@FelixKling: Ben de özgeçmişim var, ama aslında bunun dupe olmadığı ortaya çıktı: mülkiyet adının bir sayı ile başlaması veya tüm rakamlardan oluşması fark yaratır !
Jon

@Jon: Mmmh, ilginç ... tahminimden önce bir test yapmalıydı. Bana bildirdiğiniz için teşekkürler!
Felix Kling

Yanıtlar:


288

PHP 7.2 için güncellendi

PHP 7.2 , nesne ve dizi yayınlarında sayısal anahtarları dönüştürmek için davranışsal bir değişiklik getirdi bu belirli tutarsızlığı gideren ve aşağıdaki örneklerin hepsinin beklendiği gibi davranmasını sağlayan .

Kafası karıştırılacak bir şey daha az!


Orijinal cevap (7.2.0'dan önceki sürümler için geçerlidir)

PHP'nin karanlık sokaklardaki payı gerçekten içinde bulmak istemediğiniz . İsimleri sayı olan nesne özellikleri bunlardan biridir ...

Sana asla söylemedikleri

Gerçek 1: Yasal değişken adları olmayan adlara sahip mülklere kolayca erişemezsiniz

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

Aslında # 2: Sen edebilirsiniz küme ayracı sözdizimi ile böyle özelliklere erişmek

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

Aslında # 3: Ama değil özellik adı sadece rakamlardan oluşan eğer!

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

Canlı örnek .

Gerçek 4: Şey, nesne ilk etapta bir diziden gelmediği sürece.

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

Canlı örnek .

Oldukça sezgisel, katılmıyor musun?

Ne yapabilirsin

Seçenek 1: Manuel olarak yapın

En pratik yaklaşım, ilgilendiğiniz nesneyi, özelliklere erişmenizi sağlayacak bir diziye geri döndürmektir:

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

Ne yazık ki, bu yinelemeli olarak çalışmıyor. Yani senin durumunda şöyle bir şey yapman gerekecek:

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

Seçenek # 2: nükleer seçenek

Alternatif bir yaklaşım, nesneleri yinelemeli olarak dizilere dönüştüren bir işlev yazmak olabilir:

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'];

Ancak, I 'm bu gereksiz sen olduğunu tüm özelliklerinin diziler artığını çünkü bu yönüyle daha iyi bir seçenek olduğunu ikna olmadım değil senin gibi sıra ilgilenen.

Seçenek # 3: Akıllıca oynamak

Önceki seçeneğin bir alternatifi, yerleşik JSON işlevlerini kullanmaktır:

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

JSON işlevleri, herhangi bir harici işlevi tanımlamaya gerek kalmadan diziye özyinelemeli bir dönüştürme gerçekleştirir. Bununla birlikte, bu görünüme sahip olmak istenirse , seçenek # 2'nin "nükleer" dezavantajına ve ayrıca nesnenizin içinde herhangi bir dizge varsa, bu dizelerin UTF-8'de kodlanması gerektiği dezavantajına sahiptir (bu bir gerekliliktir json_encode).


Benim sorunumu da çözdü! stackoverflow.com/questions/4643894/…
Bossliaw

Jon, beni kurtardığın için teşekkürler. Yine de benim sorunum farklıydı (sanırım gerçekten "sana hiç söylemedikleri" kısmında). DB'den alınan DateTime nesnesi iyi görünüyor , ancak ->dateveya gibi özelliklerinden herhangi birine erişirsem ->timezoneyalnızca nulldöndürülür. Bu özellikleri kullanmadan önce nesneyi var_dumped edersem uygun değerlerin döndürüldüğünü fark ettim. Klonlama bunu düzeltmez, bu yüzden gerçekten erişimle bir ilgisi var sanırım var_dump... Sonra Seçenek # 1'i ve işte, ona bir dizi ( $objCastAsArray['date']) olarak erişmenin bir cazibe gibi çalıştığını gördüm .
Armfoot

1
Gerçek 0 : Dizileri nesnelere dönüştürmek ilk etapta kokuşmuş bir anlam ifade etmemelidir. Gerçek 1 ila Gerçek 3: gereksiz.
Pacerier

4
@Pacerier: Biraz sorgulanabilir olduğuna katılıyorum, ancak bazı durumlarda tamamen mantıklı olabilir. Her neyse, bu şekilde çalıştığı kılavuzda belgelendiğinden , kişisel fikirlerimiz gerçekten önemli değil.
Jon

Seçenek # 3'e UTF-8 gerektirmeyen bir alternatif şu olabilir$o = unserialize('O:8:"StdClass"' . substr(serialize($a),1));
OscarJ

10

Sadece Jon'un belagatli açıklamasına bunun neden başarısız olduğunu eklemek istedim. Bunun nedeni, bir dizi oluştururken php anahtarları tamsayılara çevirmesidir - eğer yapabiliyorsa - bu da nesnelere dönüştürülmüş dizilerde arama sorunlarına neden olur, çünkü sayısal anahtar korunur. Bu sorunludur, çünkü tüm özellik erişim seçenekleri dizeleri beklemekte veya bunlara dönüşmektedir. Aşağıdakileri yaparak bunu onaylayabilirsiniz:

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

Hangisi çıktı:

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

Dolayısıyla nesnenin biri sayısal (erişilemez) ve diğeri dize tabanlı olmak üzere iki özellik anahtarı vardır. Jon'un#Fact 4 çalışmasının , çünkü özelliği küme ayraçları kullanarak ayarlayarak, sayısal yerine her zaman dizeye dayalı bir anahtar tanımlamanız anlamına gelir.

Jon'un çözümünü alıp başını döndürerek, aşağıdakileri yaparak dizinizden her zaman dizeye dayalı anahtarlara sahip bir nesne oluşturabilirsiniz:

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

Şu andan itibaren aşağıdakilerden birini kullanabilirsiniz çünkü bu şekilde erişim, küme ayracı içindeki değeri her zaman bir dizeye dönüştürür:

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

Eski güzel mantıksız PHP ...


1

Bir nesne şöyle başlıyorsa @:

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

Kullanmalısınız:

print_r($parent_object->attributes());

çünkü $parent_object->{'@attributes'}ya $parent_object['@attributes']da çalışmayacak.


3 yıl sonra ve bu hala insanlara yardım ediyor, teşekkürler! Cevabınız sorunumu düzeltirken bir açıklaması yok. Bunun arkasındaki nedeni açıklayabilecek biri var mı?
Arbiter

1

Bu işlevi ağdan kopyalamıştım. ("StdClass Nesnelerini Çok Boyutlu Dizilere Dönüştürme Fonksiyonu") dediği gibi çalışıyorsa, aşağıdakileri deneyin:

<?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;
        }
    }

?>
  • önce dizinizi objectToArrayişleve geçirin
  • sonra dönüş değerini al
  • Eko [highlighting][448364][Data][0]

Kaynak: PHP stdClass'dan Array'e ve Array'den stdClass'a


1

Jon'un kapsamlı cevabına son bir alternatif:

İkinci parametre true olarak ayarlanmış şekilde json_decode () kullanın .

$array = json_decode($url, true);

Bu daha sonra bir nesne yerine ilişkilendirilebilir bir dizi döndürür, böylece gerçeğin ardından dönüştürmeye gerek yoktur.

Bu her uygulama için uygun olmayabilir ama oroginal nesnenin bir özelliğine kolayca atıfta bulunmamı gerçekten sağladı.

Çözüm bu öğreticide bulundu - http://nitschinger.at/Handling-JSON-like-a-boss-in-PHP/

Saygılarımızla


1

PHP 7 için

Özellik adı olarak sayılara sahip Nesne özelliklerine erişim. Çoğunlukla diziyi nesneye dönüştürdükten sonra gereklidir.

    $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

0

Korkarım, nesneleri sayısal olarak adlandırmanıza izin verilmiyor. Bir harfle başlayarak ilkini "448364" olarak yeniden adlandırın.

İkincisi bir dizidir, bunlara aşağıdaki gibi parantezlerle erişilebilir:

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

yerine


Ben değiştiremem. Çıktı, kontrolüm olmayan bir uygulamadan döndürüldü.
avinash shah
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.