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;
}
}
}
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 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"
);
I have a POST request array that looks like this
$request = array (size=2)
'licence' => string 'uDyQwFwqV7aQG2z' (length=15)
'user' =>
array (size=7)
'first_name' => string 'Danut' (length=5)
'last_name' => string 'Florian' (length=7)
'username' => string 'daniesy9' (length=8)
'password' => string '123456' (length=6)
'rpassword' => string '123456' (length=6)
'email' => string 'daniesy+1#me.com' (length=16)
'phone' => string '9903131' (length=7)
This in fact is an array which represents values sent by a form. I know the name of the elements, for example the username input has the name of user[username] and i have to find the related value from the array, by name. Something like:
$key = "user[username]";
$request[key];
Any idea how to do this?
I know that the correct way to do it is $request["user"]["username"] but it's quite complicated because i have to use the fields names from the form which are user[username], user[firstname], etc and it might have up to 4 levels of depth.
Answered in comments but similar Question to
Convert a String to Variable
eval('$username = $request["user"]["username"];');
Edit
Eval not a valid suggestion as request data.
So I would suggest the second method on this post
<?php
$request = array(
'user' => array(
'username' => 'joe_blogs'
)
);
function extract_data($string) {
global $request;
$found_matches = preg_match_all('/\[\"([a-z]+)\"\]/', $string, $matches);
if (!$found_matches) {
return null;
}
$current_data = $request;
foreach ($matches[1] as $name) {
if (key_exists($name, $current_data)) {
$current_data = $current_data[$name];
} else {
return null;
}
}
return $current_data;
}
$username = extract_data('request["user"]["username"]');
?>
function findInDepth($keys, $array){
$key = array_shift($keys);
if(!isset($array[$key])){
return FALSE;
}
if(is_array($array[$key])){
return findInDepth($keys, $array[$key]);
}
return $array[$key];
}
$key = "user[username]";
$keys = preg_split("/(\[|\])/", $key);
echo findInDepth($keys, $request);
This function solves my problem. It first splits the string (aka the input name) into an array of keys and then recessively searches in depth the array by keys until it finds a value which is not an array and returns FALSE otherwise.
You could separate keys with dots. Primitive example:
<?php
class ArrayDot
{
protected $array = [];
public function __construct(array $array) {$this->array = $array;}
public function get($path)
{
$array = $this->array;
foreach(explode('.', $path) as $key) {
$array = $array[$key];
}
return $array;
}
}
$array = [
'user' => [
'username' => 'tootski',
]
];
$a = new ArrayDot($array);
echo $a->get('user.username'); # tootski
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.'>';
}
}
}
}
}