I need to access the data: 'hotelID', 'name', 'address1','city' etc. I have the following Std Object array ($the_obj) in PHP that contains the following data:
object(stdClass)[1]
public 'HotelListResponse' =>
object(stdClass)[2]
public 'customerSessionId' => string '0ABAAA87-6BDD-6F91-4292-7F90AF49146E' (length=36)
public 'numberOfRoomsRequested' => int 0
public 'moreResultsAvailable' => boolean false
public 'HotelList' =>
object(stdClass)[3]
public '#size' => string '227' (length=3)
public '#activePropertyCount' => string '227' (length=3)
public 'HotelSummary' =>
array (size=227)
0 =>
object(stdClass)[4]
public 'hotelId' => 112304
public 'name' => La Quinta Inn and Suites Seattle Downtown
public 'address1' => 2224 8th Ave
public 'city' => Seattle
public 'stateProvinceCode' => WA
public 'postalCode' => 98121
public 'countryCode' => US
public 'airportCode' => SEA
public 'propertyCategory' => 1
public 'hotelRating' => 2.5
I have tried the following for lets say to access the 'name':
echo $the_obj->HotelListResponse->HotelList->HotelSummary[0]->name;
Also I have tried to print each key and value pairs by using foreach loop but I keep on getting errors. Here is what I tried:
foreach ($the_obj->HotelListResponse->HotelList->HotelSummary[0] as $key => $value){
echo $key.' : '.$value.'<br />';
}
Here are the errors that I get:
Trying to get property of non-object
Warning: Invalid argument supplied for foreach()
Thank you everyone for answering, I have figured out the way to access the 'hotelID', 'name' and all other keys and value pairs in the deepest nest of the array.
I converted the Std Object array to an associative array, then I accessed each of the value by using the foreach loop:
foreach ($the_obj["HotelListResponse"]["HotelList"]["HotelSummary"] as $value){
echo $value["hotelId"];
echo $value["name"];
//and all other values can be accessed
}
To access both (Keys as well as values):
foreach ($the_obj["HotelListResponse"]["HotelList"]["HotelSummary"] as $key=>$value){
echo $key.'=>'.$value["hotelId"];
echo $key.'=>'.$value["name"];
//and all other keys as well as values can be accessed
}
Regarding to #Satya's answer I'd like to show simpler way for Object to array conversion, by using json functions:
$obj = ...
$tmp = json_encode($obj);
$objToArray = json_decode($tmp,true);
This way you can easily access array items. First you can dump structure...
try something like this :
$p=objectToArray($result);
recurse($p);
}
function objectToArray( $object )
{
if( !is_object( $object ) && !is_array( $object ) )
{
return $object;
}
if( is_object( $object ) )
{
$object = get_object_vars( $object );
}
return array_map( 'objectToArray', $object );
}
function recurse ($array)
{
//statements
foreach ($array as $key => $value)
{
# code...
if( is_array( $value ) )
{
recurse( $value );
}
else
{ $v=$value;
$v=str_replace("’",'\'',strip_tags($v));
$v=str_replace("–",'-',$v);
$v=str_replace("‘",'\'',strip_tags($v));
$v=str_replace("“",'"',strip_tags($v));
$v=str_replace("”",'"',strip_tags($v));
$v=str_replace("–",'-',strip_tags($v));
$v=str_replace("’",'\'',strip_tags($v));
$v=str_replace("'",'\'',strip_tags($v));
$v=str_replace(" ",'',strip_tags($v));
$v=html_entity_decode($v);
$v=str_replace("&",' and ',$v);
$v = preg_replace('/\s+/', ' ', $v);
if($key=="image")
{
if(strlen($v)==0)
{
echo '<'.$key .'>NA</'.$key.'>';
}
else
{
echo '<'.$key .'>'. trim($v) .'</'.$key.'>';
}
}
}
}
}
Related
I have an array of associative array, I will like to update the values in this array, hence I created a function that looks like this.
//The Array of Associative arrays
array (size=2)
0 =>
array (size=3)
'slang' => string 'Tight' (length=5)
'description' => string 'Means well done' (length=15)
'example-sentence' => string 'Prosper it Tight on that job' (length=28)
1 =>
array (size=3)
'slang' => string 'Sleet' (length=5)
'description' => string 'Means to send on long errand' (length=28)
'example-sentence' => string 'I am going to sleep sia' (length=23)
//The function
public function update($slang, $new)
{
array_map(function($data, $key) use($slang, $new)
{
if($data['slang'] == $slang)
{
$data[$key] = array_replace($data, $new);
}
}, UrbanWord::$data);
}
I tired running this but the original array will not update. I need help on how to go about fixing this please.
Thanks
You may use array_reduce instead of array_map as following:
public function update($array, $slang, $new)
{
return array_reduce($array, function ($result, $item) use ($slang, $new) {
if ($item['slang'] == $slang) {
$item = array_replace($item, $new);
}
$result[] = $item;
return $result;
}, array());
}
Usage:
UrbanWord::$data = $this->update(
UrbanWord::$data,
'Tight',
array('description' => 'another description')
);
var_dump($myUpdatedArray);
If you want to update it directly passing the UrbanWord::$data by reference you may try something like:
class UrbanWord
{
public static $data = array(
array(
'slang' => 'Test',
'Desc' => 'Frist Desc'
),
array(
'slang' => 'Test1',
'Desc' => 'Second Desc'
)
);
}
class MyClass
{
public function update(&$array, $slang, $new)
{
$array = array_reduce($array, function ($result, $item) use ($slang, $new) {
if ($item['slang'] == $slang) {
$item = array_replace($item, $new);
}
$result[] = $item;
return $result;
}, array());
}
}
$myClass = new MyClass();
$myClass->update(UrbanWord::$data, 'Test', array('Desc' => 'test'));
echo '<pre>';
var_dump(UrbanWord::$data);
echo '</pre>';
This is a typical array structure:
$s = array ('etc'=>'etc', 'fields' =>
array (
0 => array (
'name'=>'year', 'description'=>'Year of ...', 'type'=>'integer',
),
1 => array (
'name'=>'label', 'description'=>'Offical short name', type'=>'string',
),
2 => array (
'name' => 'xx', 'description' => 'Xx ...', 'type' => 'string',
)
));
Here is a non-elegant way (or "not so elegant way") to reduce the big array to a simple array containing just one column:
$fields = array();
foreach ($strut['resources'][0]['schema']['fields'] as $r)
$fields[] = $r['name'];
This works, but is it possible to do the same with only one instruction? Perhaps using like array_reduce(), but I not see how.
Here are other typical "elegance PHP problem":
$fieldsByName = array();
foreach ($strut['resources'][0]['schema']['fields'] as $r)
$fields[$r['name']] = array(
'description' =>$r['description'],
'type' =>$r['type']
);
Is there a PHP alternative? The idea here is to use the keyword (name in the example) as an array key, and the other elements as usual fields, so, the generic non-elegant algorithm is
$fieldsByName = array();
foreach ($strut['resources'][0]['schema']['fields'] as $r){
$key = $r['name'];
unset($r['name']);
$fields[$key] = $r;
}
You can use array_column to extract all values with key name into another array
$names = array_column($strut['resources'][0]['schema']['fields'], 'name');
you could put your array thru this function:
function flatten(array $array) {
$return = array();
array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
return $return;
}
it will result in just a literal sequence of just values of your multidimensional array, like so.
Array
(
[0] => etc
[1] => year
[2] => Year of ...
[3] => integer
[4] => day
[5] => Day of the ...
[6] => string
[7] => xx
[8] => Xx ...
[9] => string
)
then, as you know original structure - you can parse this how needed. 4ex: every third value could be new assoc array's key value that holds an array with arrays of first two values.., or as you wish
array_column is first logical announcement, no surprises there.
Depending on how normalized your data is and how often this issues comes up, you could implement a class around your data. You can use the ArrayAccess, Iterator and Countable to make the change completely transparent, and you would be able to implement helper methods to hide the complexity of fetching data.
Here is an example, just using ArrayAccess:
class Strut implements ArrayAccess {
private $data;
private $fieldsByName = null;
public function __construct($data) {
$this->data = $data;
}
public function fieldsByName() {
//If the result has not already been computed
if($this->fieldsByName === null) {
$this->fieldsByName = array();
foreach($this->data['resources'][0]['schema']['fields'] as $r) {
$this->fieldsByName[ $r['name'] ] = array(
'description' =>$r['description'],
'type' =>$r['type']
);
}
}
return $this->fieldsByName;
}
/**
* ArrayAccess Methods
*/
public function offsetSet($offset, $value) {
$this->data[$offset] = $value;
}
public function offsetExists($offset) {
return isset( $this->data[$offset] );
}
public function offsetUnset($offset) {
unset( $this->data[$offset] );
}
public function offsetGet($offset) {
return isset( $this->data[$offset] ) ? $this->data[$offset] : null;
}
}
Using the above code you should be able to access your data just has you have been, but you also have the option of defining additional accessors in a nice container. Note that you also have to implement the Iterator interface to be able to foreach over your data.
This doesn't address the "elegance" issue of the underlying implementation (the other solutions do a nice job of that), but this way hides the complexity completely.
I spent over 2 hours looking for the solution, and I leave it to you because I am completely blocked. I try to learn the object in PHP. I created a function that return me the result of an SQL query.
Here is the var_dump return :
object(stdClass)[6]
public 'name' =>
array (size=2)
0 =>
object(stdClass)[11]
public 'id' => string '1' (length=1)
1 =>
object(stdClass)[12]
public 'id' => string '5' (length=1)
I used a foreach to parse this, but I don't get directly the id of each element. And I especially don't want to use another foreach.
foreach($function as $key => $value){
var_dump($value->id);
}
But it doesn't work there.
Here is the function called who returns this result
public function nameFunction () {
$obj = new stdClass();
$return = array();
$request = $this->getConnexion()->prepare('SELECT id FROM table') or die(mysqli_error($this->getConnexion()));
$request->execute();
$request->store_result();
$request->bind_result($id);
while ($request->fetch()) {
$return[] = parent::parentFunction($id);
}
$obj->name = $return;
$request-> close();
return $obj;
}
And parent::parentFunction($id) returns :
object(stdClass)[11]
public 'id' => string '1' (length=1)
You are looping the object instead of array. Try to use this code
foreach($function->name as $key => $value){
var_dump($value->id);
}
Tell me if it works for you
This question might help you :
php parsing multidimensional stdclass object with arrays
Especially answer from stasgrin
function loop($input)
{
foreach ($input as $value)
{
if (is_array($value) || is_object($value))
loop($value);
else
{
//store data
echo $value;
}
}
}
I am writing a class to sanitize strings passed to PHP through an ajax call, when I pass a string into this class it works fine but passing the array as a reference and it won't work.
class Sanitize {
public static function clean (&$str) {
self::start($str);
}
public static function cleanArray (&$array) {
if (self::arrayCheck($array)) {
foreach ($array as $key => $value) {
if (self::arrayCheck($value)) {
self::cleanArray($value);
} else {
self::clean($value);
}
}
} else {
throw new Exception ('An array was not provided. Please try using clean() instead of cleanArray()');
}
}
private static function start (&$str) {
$str .= '_cleaned';
}
private static function arrayCheck ($array) {
return (is_array($array) && !empty($array));
}
}
Test Code:
$array = array(
'one' => 'one',
'two' => 'two',
'three' => 'three',
'four' => 'four'
);
echo print_r($array, true) . PHP_EOL;
Sanitize::cleanArray($array);
echo print_r($array, true) . PHP_EOL;
Output:
Array
(
[one] => one
[two] => two
[three] => three
[four] => four
)
Array
(
[one] => one
[two] => two
[three] => three
[four] => four
)
Is there something I am missing, or is it not possible to nest reference passes in PHP?
You lose the reference inside the foreach. Change it to this and it'll work:
foreach( $array as $key => &$value ) {
Your code does not modify the $array, it modifies $value.
There're couple of ways to get around that, one is foreach ($array as &$value), the other is modify $array[$key] inside the loop.
I have an array where I need the path (keys) to a given value. I've written a function for it but I can't get it working, the array can have an infinite depth to be controlled in another function, I haven't decided on a limit yet but the depth is variable, it actually works up to a point but the depth may be 30-40-50 deep so I need it to work that way, this function is really just for value identification, the numbers are templates, the tags are tags in the templates, each tag has a single template associated with it, all template names are unique and tags names aren't because they are only associated with a single template, id values are separated by a dash (illegal in template and tag ids), where template ids are only numeric and tag ids are wrapped with squigglies and a dollar sign like so {$TAG}, don't have to worry about duplicate values because infinite loops are forbidden (template can't link to itself or a template that links to itself) plus ids are given only to templates where template names are unique. The id of the template named 4 in the given array would be 0-{$CONTENT}-2-{$PARAGRAPH}-4, where I lose it is my function won't go beyond this depth, thanks for the help
array (size=1)
0 =>
array (size=4)
'{$TITLE}' => null
'{$NAME}' => null
'{$FRIENDS}' =>
array (size=1)
1 =>
array (size=2)
'{$friend}' => null
'{$friends[$i]}' => null
'{$CONTENT}' =>
array (size=1)
2 =>
'{$HEADING}' =>
array (size=1)
3 =>
array (size=0)
empty
'{$PARAGRAPH}' =>
array (size=1)
4 =>
array (size=1)
'{$AnotherParagraph}' => null
here is my function, I've added the depth variable just for testing purposes, $this->family is the array given above, calling the function: $id = $this->get_id(4);
public function get_id($member, $family=null, $id=null, $depth=0) {
if (empty($this->family)) {
return false;
}
if (is_null($family)) {
$family = $this->family;
}
foreach ($family as $parent => $tag_child) {
if ($member === $parent) {
return $member;
}
foreach ($tag_child as $tag => $child) {
if (is_null($child) || empty($child)) {
continue;
}
$childkey = key($child);
if ($member === $childkey) {
$id .= '-'.$parent.'-'.$tag.'-'.$member;
$id = ltrim($id, '-');
return $id;
}
$family = $child;
if (!is_null($id) && !empty($id)) {
$id_array = explode('-', $id);
foreach ($id_array as $id_value) {
if ($id_value !== $childkey) {
$new_id_array[] = $id_value;
}else{
break;
}
}
$id = implode('-', $new_id_array);
}
if ($parent === 0) {
$id = $parent.'-'.$tag.'-'.$childkey;
}else{
$id .= '-'.$tag.'-'.$childkey;
}
$id = ltrim($id, '-');
$depth++;
$id = $this->get_id($member, $family, $id, $depth);
}
}
}
Use a recursive function. Here's one I wrote for this EXACT purpose.
public function recurseArray($array, $builtKey = "") {
$values = array();
foreach ($array as $key => $value) {
if (is_array($value)) {
if (!empty($builtKey)) {
$values = array_merge($values, recurseArray($value, $builtKey.".".$key));
} else {
$values = array_merge($values, recurseArray($value, $key));
}
} else {
if (!empty($builtKey)) {
$values[$builtKey.".".$key] = $value;
} else {
$values[$key] = $value;
}
}
}
return $values;
}
This results in a flat array that transforms this:
array(
"key" => array(
"of" => array(
"many" => array(
"depths" => "value"
)
)
),
"key2" => "value"
);
Into this:
array(
"key.of.many.depths" => "value",
"key2" => "value"
);