3

I have a PHP object and I am trying to get the value by the key without using a foreach.

If I do the below I am able to get the value:

$item_data_decode->meta_data[0]->value;

but the items may be in different orders so cannot count on this method and I need to use the key however this doesn't work:

$item_data_decode->meta_data['First Name'];

Code:

$item_data_decode = json_decode($item_values);
if (!empty($item_data_decode->meta_data)) {
    $fName = $item_data_decode->meta_data['First Name']->value;
}

Object:

$a = new stdClass();
$a->meta_data = array();
$a->meta_data[0] = new stdClass();
$a->meta_data[0]->id = "2113";
$a->meta_data[0]->key = "First Name";
$a->meta_data[0]->value = "Recipient First Name";
$a->meta_data[1] = new stdClass();
$a->meta_data[1]->id = "2114";
$a->meta_data[1]->key = "Last Name";
$a->meta_data[1]->value = "Recipient Last Name";
$a->meta_data[2] = new stdClass();
$a->meta_data[2]->id = "2115";
$a->meta_data[2]->key = "addressLine 1";
$a->meta_data[2]->value = "Recipient Address Line 1";
$a->meta_data[3] = new stdClass();
$a->meta_data[3]->id = "2116";
$a->meta_data[3]->key = "addressLine2";
$a->meta_data[3]->value = "Recipient Address Line 2";
$a->meta_data[4] = new stdClass();
$a->meta_data[4]->id = "2117";
$a->meta_data[4]->key = "City";
$a->meta_data[4]->value = "Recipient Town/City";
$a->meta_data[5] = new stdClass();
$a->meta_data[5]->id = "2118";
$a->meta_data[5]->key = "Region";
$a->meta_data[5]->value = "Recipient Region/County";
$a->meta_data[6] = new stdClass();
$a->meta_data[6]->id = "2119";
$a->meta_data[6]->key = "Country";
$a->meta_data[6]->value = "N/A";
$a->meta_data[7] = new stdClass();
$a->meta_data[7]->id = "2120";
$a->meta_data[7]->key = "Postcode";
$a->meta_data[7]->value = "Recipient Postcode";


// outputs
[meta_data] => Array ( [0] => stdClass Object ( [id] => 2113 [key] => First Name [value] => Recipient First Name ) [1] => stdClass Object ( [id] => 2114 [key] => Last Name [value] => Recipient Last Name ) [2] => stdClass Object ( [id] => 2115 [key] => addressLine 1 [value] => Recipient Address Line 1 ) [3] => stdClass Object ( [id] => 2116 [key] => addressLine2 [value] => Recipient Address Line 2 ) [4] => stdClass Object ( [id] => 2117 [key] => City [value] => Recipient Town/City ) [5] => stdClass Object ( [id] => 2118 [key] => Region [value] => Recipient Region/County ) [6] => stdClass Object ( [id] => 2119 [key] => Country [value] => N/A ) [7] => stdClass Object ( [id] => 2120 [key] => Postcode [value] => Recipient Postcode ) )

Adding true to the json_decode provides the following:

Array ( [id] => 232 [order_id] => 320 [name] => Tb [product_id] => 50 [variation_id] => 0 [quantity] => 1 [tax_class] => [subtotal] => 50 [subtotal_tax] => 0 [total] => 50 [total_tax] => 0 [taxes] => Array ( [total] => Array ( ) [subtotal] => Array ( ) ) [meta_data] => Array ( ) ) Array ( [id] => 233 [order_id] => 320 [name] => Turtle Bay Gift Card [product_id] => 50 [variation_id] => 0 [quantity] => 1 [tax_class] => [subtotal] => 30 [subtotal_tax] => 0 [total] => 30 [total_tax] => 0 [taxes] => Array ( [total] => Array ( ) [subtotal] => Array ( ) ) [meta_data] => Array ( [0] => Array ( [id] => 2113 [key] => First Name [value] => Recipient First Name ) [1] => Array ( [id] => 2114 [key] => Last Name [value] => Recipient Last Name ) [2] => Array ( [id] => 2115 [key] => addressLine 1 [value] => Recipient Address Line 1 ) [3] => Array ( [id] => 2116 [key] => addressLine2 [value] => Recipient Address Line 2 ) [4] => Array ( [id] => 2117 [key] => City [value] => Recipient Town/City ) [5] => Array ( [id] => 2118 [key] => Region [value] => Recipient Region/County ) [6] => Array ( [id] => 2119 [key] => Country [value] => N/A ) [7] => Array ( [id] => 2120 [key] => Postcode [value] => Recipient Postcode ) ) )
1
  • Your JSON is wrong. Change that and you will be good to go Commented Oct 17, 2017 at 22:03

3 Answers 3

4

Accessing each property is how you normally access a property of an object.
Note that since "First name" has a space, it cannot be accessed by the arrow notation and must be enclosed in curly braces. For any property that doesn't have a space, there is no need for the curly braces.

The reason your code was failing is because you were trying to access properties using the square bracket notation used for arrays.

I am aware that you are not able to edit the actual array output, but if you can edit the JSON then this will solve your problems.

{
    "meta_data": {
        "First name": {
            "id": 2113,
            "key": "First name",
            "value": "Recipient First Name"
        },
        "Last Name": {
            "id": 2114,
            "key": "Last Name",
            "value": "Recipient Last Name"
        },
        "addressLine 1": {
            "id": 2115,
            "key": "addressLine 1",
            "value": "Recipient Address Line 1"
        },
        "addressLine2": {
            "id": 2116,
            "key": "addressLine2",
            "value": "Recipient Address Line 2"
        },
        "City": {
            "id": 2117,
            "key": "City",
            "value": "Recipient Town/City"
        },
        "Region": {
            "id": 2118,
            "key": "Region",
            "value": "Recipient Region/County"
        },
        "Country": {
            "id": 2119,
            "key": "Country",
            "value": "N/A"
        },
        "Postcode": {
            "id": 2120,
            "key": "Postcode",
            "value": "Recipient Postcode"
        }
    }
}

var_dump($item_data_decode->meta_data->{"First name"}->value); // outputs "Recipient First Name"
Sign up to request clarification or add additional context in comments.

Comments

3

Personally I would prepare the data like this:

$item_data_decode = json_decode($item_values, true);
$meta_array = array_combine(array_column($item_data_decode['meta_data'], 'key'), $item_data_decode['meta_data']);

if (!empty($meta_array['First Name'])) {
  $fName = $meta_array['First Name']['value'];
}

The second param in json_decode makes sure it returns only arrays (Manual.). This way you can use array function like array_column (Manual) and array_combine(Manual), and get an array that is very close to the structure you want.

Test Case, since no code is to short for it.

6 Comments

I completely failed to realize that the OP didn't pass true in as a second parameter to json_decode(). That alone should resolve the issue completely.
This didn't work for me. the $meta_array['First Name'] doesn't return true. Also simply adding true did not work with the original code.
@Ben Damn. I thought I could get away without testing. Give me a few minutes and I update the answer.
no problem! I thought i may have needed to add ['meta_data'] before the first name but that didn't resolve the issue.
I edited the answer. I'm embarrassed to say that it had two independent mistakes. I left $item_data_decode->meta_data, after changing the variable to an array, and simply forgot the array combine part.
|
0

If you can modify the array structure, then structure it like this:

array(
    'First Name'=>array(
        'id'=>2113,
        'value'=>'Recipient First Name'
    ),
    'Last Name'=>array(
        'id'=>2114,
        'value'=>'Recipient Last Name'
    ),
    . . .
);

You can then still use this array in a foreach loop as before if needed, albeit with some changes, while being able to access the value you want directly.

If you can't modify the array structure, then you're out of luck and a foreach loop is required if you want to find the value you want.

If your concern is performance of accessing the array multiple times, then consider transforming the array to the structure above before processing.

Edit

Example array transformation:

$transformed_array = array();
foreach($item_data_decode->meta_data as $data) {
    $transformed_array[$data['key']] = array(
        'id'=>$data['id'],
        'value'=>$data['value']
    );
}

5 Comments

Unfortunately cannot modify the array structure as it is generated by WooCommerce. So the only way is to do a foreach for each of my applicable keys?
Correct. But, as I mentioned, if you're going to be accessing more than one key, you should transform the array first into an associative array. This will allow you to take your potentially n array access actions over n different keys which would be an O(n^2) algorithm, and move it to n transform actions and then n array access actions for an O(n+n) = O(n) algorithm, reducing your time complexity by a factor of n. Also, your code will be a lot cleaner and easier to maintain :)
Thank you @B.Flemming Are you able to point me in the right direction for documention on how to do this?
I've provided an example array transformation in an edit at the bottom of my answer. Feel free to test it to see if it works. The idea, essentially, is that you iterate through the original array, take the key, as the key for the new array, and assign the remaining key/value pairs to that key.
@BenH Please look at the other answer here. Adding true as a second parameter value to json_encode() might do all of this for you automatically and save you a lot of hassle!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.