4

Earlier I have some block of code and it was working fine, But in some case it is throwing PHP notice:

Here is the code:

$json = '{"1455260079":"Tracking : #34567808765098767 USPS","1455260723":"Delivered","1455261541":"Received Back"}';

$json_obj = json_decode($json);
$json_array = (array) $json_obj;
var_dump($json_array);
print_r($json_array);

echo $json_array["1455260079"]."\n";

output:

array(3) {
  ["1455260079"]=>
  string(34) "Tracking : #34567808765098767 USPS"
  ["1455260723"]=>
  string(9) "Delivered"
  ["1455261541"]=>
  string(13) "Received Back"
}
Array
(
    [1455260079] => Tracking : #34567808765098767 USPS
    [1455260723] => Delivered
    [1455261541] => Received Back
)

Notice: Undefined index: 1455260079 in /in/PULrp on line 14

So I changed above code with below code and it's working fine.

$json_array = json_decode($json, true);
var_dump($json_array);
print_r($json_array);
echo $json_array["1455260079"]."\n";

output:

array(3) {
  [1455260079]=>
  string(34) "Tracking : #34567808765098767 USPS"
  [1455260723]=>
  string(9) "Delivered"
  [1455261541]=>
  string(13) "Received Back"
}
Array
(
    [1455260079] => Tracking : #34567808765098767 USPS
    [1455260723] => Delivered
    [1455261541] => Received Back
)
Tracking : #34567808765098767 USPS

But Here I am a bit confused why (array) type casting conversion is not working in this code. I know json_decode($json, true) is best option to convert json string into array but $json_array = (array) $json_obj; is also a valid option.

While looking into var_dump of both code it showing some difference but the print_r of both array are exactly same.

I am curious to know why such different occurred in var_dump of both and how (array) type casting is converting object to array in first case?

I also noticed that it's happening if the key is number i.e. 1455260079 in my case, if I change key 1455260079 to some string its working as expected.

you can see output of the complete code at: https://3v4l.org/PULrp

GuRu
  • 1,880
  • 3
  • 23
  • 32
Chetan Ameta
  • 7,696
  • 3
  • 29
  • 44

2 Answers2

3

A few findings I have here:

Quoted from:

  1. A numeric string as array key in PHP
  2. http://www.php.net/manual/en/language.types.array.php

They state that:

Strings containing valid integers will be cast to the integer type. E.g. the key "8" will actually be stored under 8. On the other hand "08" will not be cast, as it isn't a valid decimal integer.

What's interesting is (slightly modifying your test script):

<?php
$json = '{"1455260079":"Tracking : #34567808765098767 USPS","1455260723":"Delivered","1455261541":"Received Back"}';

$json_obj = json_decode($json);
$json_array = (array) $json_obj;
var_dump($json_array);
print_r($json_array);

$newerArray = array();

echo "json_array contents: \n";
foreach($json_array as $k => $v){
    echo "k: $k " . gettype($k) . ", v: $v " . gettype($v) . "\n";
    $newerArray[$k] = $v;
}

echo "\n";

echo "newerArray contents: \n";
foreach($newerArray as $k => $v){
    echo "k: $k " . gettype($k) . ", v: $v " . gettype($v) . "\n";
}

echo $json_array["1455260079"]."\n";
echo $newerArray["1455260079"]."\n";

The output is:

array(3) {
  ["1455260079"]=>
  string(34) "Tracking : #34567808765098767 USPS"
  ["1455260723"]=>
  string(9) "Delivered"
  ["1455261541"]=>
  string(13) "Received Back"
}
Array
(
    [1455260079] => Tracking : #34567808765098767 USPS
    [1455260723] => Delivered
    [1455261541] => Received Back
)
json_array contents: 
k: 1455260079 string, v: Tracking : #34567808765098767 USPS string
k: 1455260723 string, v: Delivered string
k: 1455261541 string, v: Received Back string

newerArray contents: 
k: 1455260079 integer, v: Tracking : #34567808765098767 USPS string
k: 1455260723 integer, v: Delivered string
k: 1455261541 integer, v: Received Back string

Notice: Undefined offset: 1455260079 in /in/Eq1OI on line 24

Tracking : #34567808765098767 USPS

Notice the type of the key in of two arrays - the casted array have (numeric) string keys, while the reassigned array have integer keys.

When you cast the object to an array, the key is somehow still a string. This is not expected by the PHP definition of an array, according to the quote above.

So when you try to access the array with a "numeric string", PHP still treats the string as an integer, but internally, the keys are still strings, resulting in a undefined array.

This also implies that for associative arrays, key comparisons are actually strict but practically loose.

Community
  • 1
  • 1
kazenorin
  • 1,455
  • 8
  • 16
  • so basically its not worthy to use `(array)` type cast, as it will change the whole behavior of the flow? – Chetan Ameta Apr 06 '16 at 09:29
  • 1
    Unless you have no integer keys on your object, otherwise it seems that an `(array)` type cast should be avoided, as pointed out by @limekin 's answer. – kazenorin Apr 06 '16 at 09:46
3

Reasons are given in the PHP Manual itself.

First case (undefined index error):

$json_array = (array) $json_obj;

Given in Converting to array :

If an object is converted to an array, the result is an array whose elements are the object's properties. The keys are the member variable names, with a few notable exceptions: integer properties are unaccessible; ...

So you should use json_decode($json_string, true) to get an associative array.

Second case (differences with print_r and var_dump) :

Given in var_dump Description :

This function displays structured information about one or more expressions that includes its type and value. Arrays and objects are explored recursively with values indented to show structure.

And in Return Values of print_r :

If given a string, integer or float, the value itself will be printed. If given an array, values will be presented in a format that shows keys and elements. Similar notation is used for objects.

So strings will be printed with qoutes with var_dump and without qoutes in print_r.

limekin
  • 1,934
  • 1
  • 12
  • 15