I got an object that has some private properties that i cannot access.
var_dump($roomType);
// I deleted some of the results of var_dump
object(MPHB\Entities\RoomType)#2003 (6) {
["id":"MPHB\Entities\RoomType":private]=> int(15)
["originalId":"MPHB\Entities\RoomType":private]=> int(15)
["description":"MPHB\Entities\RoomType":private]=> string(0) ""
["excerpt":"MPHB\Entities\RoomType":private]=> string(0) ""
["imageId":"MPHB\Entities\RoomType":private]=> int(406)
["status":"MPHB\Entities\RoomType":private]=> string(7) "publish" }
So I convert the object to array.
$array = (array) $roomType;
print_r($array);
/*
Array (
[MPHB\Entities\RoomTypeid] => 15
[MPHB\Entities\RoomTypeoriginalId] => 15
[MPHB\Entities\RoomTypedescription] =>
[MPHB\Entities\RoomTypeexcerpt] =>
[MPHB\Entities\RoomTypeimageId] => 406
[MPHB\Entities\RoomTypestatus] => publish )
*/
but I still cannot access the values from key like this
var_dump($array["MPHB\Entities\RoomTypeimageId"]); // NULL
The only workaround i got is this :
$array = (array) $roomType;
$array_keys = array_keys($array);
$array_key_id = $array_keys[4];
echo $array[$array_key_id]; // 406
But I am not sure that the key is at the same position all the time, so I want to find an other way.
I escaped the slashes but still the same, any ideas?
Edit :
So I tried to compare the $array_key_id (which is MPHB\Entities\RoomTypeimageId) with the same value (copied from the browser) and it fails.
So I did a loop and pushed the key=>value to the existing $array and now I can get the value.
There must be something like null bytes as BacLuc said.
I would guess that escaping is the problem:
$array["MPHB\Entities\RoomTypeimageId"] -> $array["MPHBEntitiesRoomTypeimageId"] for which there is no value in the array.
But $array["MPHB\\Entities\\RoomTypeimageId"] might work.
Edit:
it's escaping plus on private properties have the class name prepended to the property name, surrounded with null bytes.
Test is here: http://sandbox.onlinephpfunctions.com/code/d218d41f22e86dd861f562de9c040febb011d577
From:
Convert a PHP object to an associative array
https://www.php.net/manual/en/language.types.array.php#language.types.array.casting
Related
I have a returned string result from an API and it looks like this.. for the life of me, I cannot retried the WorkID value!
The returned string is a json string:
{"notes":"","RecordsStatus":"{\"0\":{\"WorkID\":\"0090210\",\"Message\":\"Record Created\"}}"}
It has two parts:
“notes” and “RecordStatus”.
If message is empty, means the batch is imported without error.
In RecordStatus, there are two parts too.
First is the index number of the record, and it has second part that the key for the record created(in my case it’s the WorkID) and a message tells the record is created or updated(in my case, it’s created).
Array
(
[notes] =>
[RecordsStatus] => {"0":{"WorkID":"0090210","Message":"Record Created"}}
)
Do a Var_dump() of decoded_json results in this:
array(2) {
["notes"]=>
string(0) ""
["RecordsStatus"]=>
string(52) "{"0":{"WorkID":"0090210","Message":"Record Created"}}"
}
I tried
foreach($decoded_json as $item) {
$uses = $item['RecordsStatus'][0]['WorkID']; //etc
}
but does not work
I'm stuck with a very weird bug. I have an object called $row that looks like this:
stdClass Object
(
[title] => Some Title
[body] => My body
[topic] => Topic
[dataType] => Survey
[csvrownum] => 1
)
I'm just trying to print out the title property in the following way:
print_r($row->title);
However for some reason that doesn't output anything.
Then I've tried to manually set the title property and print it right after, something like this:
$row->title = 'My Title';
print_r($row->title);
Surprisingly it worked but why? To make this more strange I decided to var_dump the object after set the title variable by hand:
$row->title = 'My Title';
var_dump($row);
And this is what I've got:
class stdClass#391 (6) {
public $title =>
string(3) "Some title"
public $body =>
string(7) "My body"
public $topic =>
string(6) "Topic"
public $dataType =>
string(17) "Survey"
public $csvrownum =>
int(1)
public $title =>
string(8) "My title"
}
Notice the title key is duplicated with different values. Is there any condition under this could happen?
No, PHP does not allow an object to have duplicate property names, because objects in PHP are implemented just like arrays. They are both implemented as ordered hashmaps. In a hashmap, two things that have the same hash, overwrite each other.
You likely just have unprintible characters in your object property name. You can see this more clearly by doing something like the following for debug purposes...
foreach($row as $key => $value) {
var_dump($key);
}
If we had an object like this, for example, you'd see it gets overwritten.
$row = new stdClass;
$row->title = "First";
$row->title = "Second";
But something like this might be more deceptive...
$row = new stdClass;
$row->{"title\0"} = "First";
$row->title = "Second";
Output from the foreach using var_dump on the key, would reveal this...
string(6) "title"
string(5) "title"
Notice one is string of length 6 and the other is a string of length 5.
Grain of salt
It's always better to use var_dump when attempting to debug variables than using something like print_r, as var_dump was specifically designed for debug purposes, whereas print_r is just a recursive print (hence the name). Printing values like null, false, or empty strings, gives you no useful information for debug purposes, but var_dump does.
Given the following array:
$array = array(
'item_1' => array(
'item_1_1' => array(
'item_1_1_1' => 'Hello',
),
'item_1_2' => 'World',
),
'item_2' => array(),
);
How can I convert that into an Object?
Option 1
$obj = (object) $array;
Or
Option 2
$object = json_decode(json_encode($array), FALSE);
Or something else?
I would like to know the difference in the output between the 2 option and understand the best practice for creating this conversion.
Well you are answering somehow your own question, but if you want to have an object with the attributes like your array you have to cast it, this way an array will remain an array
$obj = (object) $array;
OUTPUT:
object(stdClass)#1 (2) {
["item_1"]=>
array(2) {
["item_1_1"]=>
array(1) {
["item_1_1_1"]=>
string(5) "Hello"
}
["item_1_2"]=>
string(5) "World"
}
["item_2"]=>
array(0) {
}
}
if you are using the json_decode version it will convert arrays to objects too:
object(stdClass)#2 (2) {
["item_1"]=>
object(stdClass)#3 (2) {
["item_1_1"]=>
object(stdClass)#4 (1) {
["item_1_1_1"]=>
string(5) "Hello"
}
["item_1_2"]=>
string(5) "World"
}
["item_2"]=>
array(0) {
}
}
NOTE: just the empty array will be an array here.
To Answer your question: The best practice depends on what YOU need.
It depends, really: if you are working on data that might be an array in one case, and an object the next, it would probably be best to use the json_decode trick, simply because unlike a cast, its result is "recursive". There is one very important thing to keep in mind here, though: numeric indexes can, and probably will cause problems for you at some point in time. Take a look at this bug report
This is documented here, but not in a way that really stands out:
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;
Exampe of the problem:
$data = [
'foo' => 'bar',
123 => 'all is well',
];
$obj = json_decode(json_encode($data));
var_dump($obj->foo);//bar
var_dump($obj->{123});//all is well
$cast = (array) $obj;
var_dump($cast);//shows both keys
var_dump(isset($cast[123]));//FALSE!!!
var_dump(isset($cast['123']));//FALSE
Basically: If you start converting arrays to objects and back again, numeric keys are not reliable anymore. If I were you, I'd simply change the code that is passing the data where possible, or I'd create a value object that can be set using an array or an object, and normalize the data that way.
I have a html form with checkboxes. Someone selects one or more checkboxes and hit the delete button then it will delete the files references out of the database and delete the files out of Amazon S3. This is the code I used to find all the checkboxes
$checkbox_select = JRequest::getVar('checkboxselect', '', 'POST'); //just a Joomla way of doing a $_POST with extra security
var_dump($checkbox_select); //this returns: array(2) { ["video_1.mp4"]=> string(2) "on" ["video_2.mp4"]=> string(2) "on" ["video_3.mp4"]=> string(2) "on"}
// Localize and sanitize each individual value
foreach (array_keys($checkbox_select) as $element) {
$deleteNames[] = $db->quote($element);
}
var_dump($deleteNames); //array(3) { [0]=> string(13) "'video_3.mp4'" [1]=> string(13) "'video_2.mp4'" [2]=> string(13) "'video_1.mp4'" }
My problem is with Amazon S3 and multiple file deletion. The format I need to put S3 deletion in is quite confusing:
$s3->delete_objects('mybucket', array(
'objects' => array( // accepts a *list* of one or more *hashes*
// a *hash* that contains a "key" key with a value, and maybe a "version_id" key with a value
array('key' => 'object (file) name'),
// a second hash representing a file
// a third hash representing a file
// and so on...
),
));
As far as I understand (from S3 delete_objects function) the final associated array has key as the actual key value. With the last var_dump I've got all video names in an array now I just need to convert that array to a bunch of arrays in this format:
array ('key' => 'video_1.mp4'),
array ('key' => 'video_2.mp4'),
array ('key' => 'video_3.mp4'),
...and so on
How can I create these arrays? Should I be using the first var_dump I have or the second (they both have the video file names listed)? Thanks in advance.
You can use foreach to loop over your array and create a new array in the desired format.
Example:
<?php
foreach (array_keys($checkbox_select) as $element) {
$deleteNames[] = array('key' => $db->quote($element));
}
Untested, may contain errors
have a look at this post in the php documentation for array_push(). You'll get a brief idea of how to achieve it.
This is so incredibly basic that I am totally baffled as to why it doesn't work. I have an array called $elements, and I want to just echo out one of the values.
I use NetBeans as an IDE, and if I use that to examine the contents of the multidimensional array in question, it looks like this:
So far as I can tell, everything looks normal. It is a multidimensional array, where the first level is numbered "0", and the second level has four named entries.
I just want to echo the value of "parameters", which is a string.
However, this code outputs nothing:
echo "This is the value of 'parameters': " . $elements[0]['parameters'];
Have I got this most basic code wrong in some way?
This is what I get if I do var_dump($elements):
array(1) { [0]=> object(Element)#3 (4) { ["type":"Element":private]=>
string(4) "Text" ["resource":"Element":private]=> string(1) "0"
["parameters":"Element":private]=> string(209) "IP1 111.111.111.111
IP2 222.222.222.222 IP3 333.333.333.333 IP4 444.444.444.444 IP5
555.555.555.555 IP6 666.666.666.666 IP7 777.777.777.777 IP8 888.888.888.888 IP9 999.999.999.999 IP10 111.111.111.112" ["parent":"Element":private]=> NULL } }
... and this is the output from print_r($elements):
Array ( [0] => Element Object ( [type:Element:private] => Text [resource:Element:private] => 0 [parameters:Element:private] => IP1 111.111.111.111 IP2 222.222.222.222 IP3 333.333.333.333 IP4 444.444.444.444 IP5 555.555.555.555 IP6 666.666.666.666 IP7 777.777.777.777 IP8 888.888.888.888 IP9 999.999.999.999 IP10 111.111.111.112 [parent:Element:private] => ) )
Your var dump is saying that element 0 is an object, so you will need to access it like so:
echo $elements[0]->parameters;
The problem is that from your dump, the parameters element is marked as private, so you will not be able to access it.
Solutions are:
Change parameters to public
Write a getter (getParameters()) and use that method to get your parameters.
Entry 0 at $elements is not just an array of attributes it's a class Element instance so in order to access its properties do something like:
echo( $elements[ 0 ]->parameters );
Although the parameters field seems private so you'd better add an accessor method to the object like getParameters() which would be public and return the value of parameters.