How do I loop through and change values in this PHP object? - php

Here is a fairly big object dumped using print_r.
https://docs.google.com/document/d/175RLhWlMQcyhGR6ffGSsoJGS3RyloEqo4EEHCL2H2vg/edit?usp=sharing
I am trying to change the values of the uploaded_files.
Towards the end of that object you'll see something like
[uploaded_files] => Array
(
[attachment] => /home2/magician/public_html/development/testing/wp-content/uploads/wpcf7_uploads/Central-Coast-Montessori-logo.jpg
[attachment2] => /home2/magician/public_html/development/testing/wp-content/uploads/wpcf7_uploads/Andrew.jpg )
My code
// move the attachments to wpcf7ev temp folder
foreach ($cf7ev_object['uploaded_files'] as $key => $uploaded_file_path) {
$new_filepath = WPCF7EV_UPLOADS_DIR . '/' . basename($uploaded_file_path);
wpcf7ev_debug("New file path is {$new_filepath}");
rename($uploaded_file_path, $new_filepath);
wpcf7ev_debug("'{$key}'is the KEY for {$uploaded_file_path}");
wpcf7ev_debug($cf7ev_object['uploaded_files']);
$cf7ev_object['uploaded_files'][$key] = $new_filepath; // this is not updating
}
To loop through it I have been using
foreach ($cf7ev_object->uploaded_files as $key => $uploaded_file_path) {
and this has worked.
But shouldn't it be
foreach ($cf7ev_object['uploaded_files'] as $key => $uploaded_file_path) {
? As '->' is for accessing methods?
And specifically I want to update the values of those uploaded_files, so to do that I need to do
$cf7ev_object['uploaded_files'][$key] = $new_filepath; // this is not updating
? But this doesn't seem to be working.
I think I need to be clear on how to access values in an object.
Thanks.

First of all, regarding the single arrow "->" that is how you reference an objects values. But I won't get into that. Since you say it works, $cf7ev_object is obviously an object.
You say you want to "access the values in the object".
var_dump($cf7ev_object);
This will spit out what is in that object. I gather you are a bit of a newbie, so I will try to help you out best I can with the limited data you provided (you may want to expand your question.
Looping is not a one-shot deal. You can have nested loops and nested loops inside of those. However, it is a resource hog if you're not careful. Here is an exercise that might help you.
$new_array = array();
foreach($cf7ev_object->uploaded_files as $key => $value) {
$new_value = $value;//do something to the $value here
$new_array[$key] = $new_value;
}
//take a look at your work now:
print_r($new_array);
I hope this helps. Note: your google doc is restricted, public can't see it.. And your question is too vague. Let me know if I can help more.
If you want to change the object array values instantly you just set it equal to the above loop result:
$cf7ev_object->uploaded_files = $new_array;

Related

PHP extract key-value in array json and restructure

Any idea on how to restructure the json below:
$jsonArray = [{"Level":"77.2023%","Product":"Milk","Temperature":"4"},
{"Level":"399.2023%","Product":"Coffee","Temperature":"34"},
{"Level":"109.2023%","Product":"Chocolate","Temperature":"14"}]
Expected outcome:
$expected = {"Milk":{"Level":"77.2023%","Temperature":"4"},
"Coffee":{"Level":"399.2023%","Temperature":"34"},
"Chocolate":{"Level":"109.2023%","Temperature":"14"}
}
I'm new and my thinking is get the product value in array and again use foreach loop to find the others value? .
Here's one possibility:
$jsonArray = '[{"Level":"77.2023%","Product":"Milk","Temperature":"4"},
{"Level":"399.2023%","Product":"Coffee","Temperature":"34"},
{"Level":"109.2023%","Product":"Chocolate","Temperature":"14"}]';
$output = array();
foreach (json_decode($jsonArray, true) as $row) {
$product = $row['Product'];
$output[$product] = $row;
unset($output[$product]['Product']);
}
echo json_encode($output);
Output:
{"Milk":{"Level":"77.2023%","Temperature":"4"},
"Coffee":{"Level":"399.2023%","Temperature":"34"},
"Chocolate":{"Level":"109.2023%","Temperature":"14"}
}
Demo on 3v4l.org
This made some trick
$a = '[{"Level":"77.2023%","Product":"Milk","Temperature":"4"},
{"Level":"399.2023%","Product":"Coffee","Temperature":"34"},
{"Level":"109.2023%","Product":"Chocolate","Temperature":"14"}]';
$newAr = array();
foreach(json_decode($a,true) as $key=>$value)
{
$newAr[$value['Product']] = array(
'Level' => $value['Level'],
'Temperature' => $value['Temperature'],
);
}
There are many ways to perform this with Loops in PHP. Other answers demonstrate it accurately. I would also suggest to integrate some form of Error handling, data validation/filtering/restriction in your code to avoid unexpected results down the road.
For instance, json_decode(), either assigned to a variable pre-foreach or straight in the foreach() 1st argument will just raise a warning if the original json is not valid-json, and just skip over the foreach used to construct your final goal. Then if you pass the result (that may have failed) directly to your next logic construct, it could create some iffy-behavior.
Also, on the concept of data-validation & filtering, you could restrict the foreach(), or any other looping mechanism, to check against a Product_List_Array[Milk,Coffee,Chocolate], using if(in_array() ...) so the final/goal object only contains the expected Products, this, in the case the original json has other artifacts. Filtering the values can also increase stability in restricting, for example, Temperature to Float.

WordPress, MySQL, php - query results not acting as a string [duplicate]

This question already has answers here:
How to modify an array's values by a foreach loop?
(2 answers)
Closed 8 years ago.
This is driving me nuts. I've searched for solutions but can't figure out what's wrong.
The situation... I have an SQL query running in WordPress, as follows:
SELECT distinct guid
FROM $wpdb->posts
WHERE post_status = 'inherit'
AND guid is not null
Dead simple. It returns a single column which contains a list of all the attachment media files currently stored on the system (well, not all of them, but it'll do as an explanation).
In a WP plugin function, I run the query:
$media_library_files = $wpdb->get_col($get_all_media,0);
That returns an array (I don't want an object) with values like:
[0] => http://mysitename.com/wp-content/uploads/2013/05/thumb_littlefile_blah.jpg
Then I want to process each one so that there's just the filename left. The problem is that, when I run a str_replace or pretty much any other string function on the contents, it doesn't work. For example:
$horrid_bit = 'http://mysitename.com/wp-content/uploads/2013/05/';
foreach($media_library_files as $item) {
$item = str_replace($horrid_bit,'',$item);
}
When I print_r the array after that, there's no visible change - every line is exactly the same as it was before.
I've tried using a (string) to cast $item, I've tried defining variables to do that, then working the str_replace on them, I've tried... loads of different things.
I have a feeling I'm missing something really simple, but I just can't see it. Is it because the column is varchar in the original table? Or something else?
Any help appreciated. Thanks!
PHP is not my 'native languague', but it seems like you're not modifying the values in the array. Did you try to put the modified string items (=minus the path) in a new array and use that one?
$horrid_bit = 'http://mysitename.com/wp-content/uploads/2013/05/';
$new_array = array();
foreach($media_library_files as $item) {
$new_item = str_replace($horrid_bit,'',$item);
$new_array.push($new_item);
}
//...use the items in the $new_array
Also, you might wanna just read the whole path string as an array (split on '/')and take the last element to get to the file.
$horrid_bit = 'http://mysitename.com/wp-content/uploads/2013/05/';
foreach($media_library_files as $key => $value) {
$media_library_files[$key] = str_replace($horrid_bit,'', $value);
}
But as Michael pointed out if you are not doing it this way for a specific purpose using basename would be better here, so you don't have to worry about the folder changing each month/year.
foreach($media_library_files as $key => $value) {
$media_library_files[$key] = basename($value);
}
You are not actually changing the value of $item in your array, you are instead creating a new variable, which is then overwritten every time your loop iterates.
It's also a good idea to check that the array is not empty before attempting a foreach() loop on it.
Finally, I've replaced str_replace() with basename() (as suggested in the comments under your question by #MichaelBerkowski).
if(!empty($media_library_files)) : foreach($media_library_files as $item) :
$media_library_files[$item] = basename($item);
endforeach;
endif;
str_replace() can handle arrays. No need for your foreach loop.
$horrid_bit = 'http://mysitename.com/wp-content/uploads/2013/05/';
$media_library_files = str_replace( $horrid_bit,'',$media_library_files );
On the other hand, since it seems you want to remove the path and get only the filename:
foreach($media_library_files as $key => $item) {
$media_library_files[$key] = basename($item);
}
This will change all entries to the filename only. The way you have it now you will have to change the $horrid_bit every month since the uploads are organized in year/month/ folders.

PHP – Retrieving values from multi-dimensional arrays

I have a working script, but I'm sure that my method of managing arrays could be better. I've searched for a solution and haven't found one, but I'm sure that I should be using the functionality of associative arrays to do things more efficiently.
I have two arrays, one from a CSV file and one from a DB. I've created the CSV array as numeric and the DB array as associative (although I'm aware that the difference is blurry in PHP).
I'm trying to find a record in the DB array where the value in one field matches a value in the CSV array. Both arrays are multi-dimensional.
Within each record in each array there is a reference number. It appears once in the CSV array and may appear in the DB array. If it does, I need to take action.
I'm currently doing this (simplified):
$CSVarray:
('reference01', 'blue', 'small' ),
('reference02', 'red', 'large' ),
('reference03', 'pink', 'medium' )
$Dbarray:
(0 => array(ref=>'reference01',name=>"tom",type=>"mouse"),
(1 => array(ref=>'reference02',name=>"jerry",type=>"cat"),
(2 => array(ref=>'reference03',name=>"butch",type=>"dog"),
foreach ($CSVarray as $CSVrecord) {
foreach ($Dbarray as $DBrecord) {
if ($CSVarray[$numerickey] == $DBrecord['key'] {
do something with the various values in the $DBrecord
}
}
}
This is horrible, as the arrays are each thousands of lines.
I don't just want to know if matching values exist, I want to retrieve data from the matching record, so functions like 'array_search ' don't do what I want and array_walk doesn't seem any better than my current approach.
What I really need is something like this (gibberish code):
foreach ($CSVarray as $CSVrecord) {
WHERE $Dbarray['key']['key'] == $CSVrecord[$numerickey] {
do something with the other values in $Dbarray['key']
}
}
I'm looking for a way to match the values using the keys (either numeric or associative) rather than walking the arrays. Can anyone offer any help please?
use a hash map - take one array and map each key of the record it belongs to, to that record. Then take the second array and simply iterate over it, checking for each record key if the hashmap has anything set for it.
Regarding your example:
foreach ($DBarray as $DBrecord){
$Hash[$record[$key]] = $DBrecord;
}
foreach ($CSVarray as $record){
if (isset($Hash[$record[$CSVkey]])){
$DBrecord = $Hash[$record[$CSVkey]];
//do stuff with $DBrecord and $CSVrecord
}
}
this solution works at O(n) while yours at O(n^2)...
You can use foreach loops like this too:
foreach ($record as $key => $value) {
switch($key)
{
case 'asd':
// do something
break;
default:
// Default
break;
}
}
A switch may be what you are looking for also :)
Load CSV into the db, and use db (not db array) if possible for retrieval. Index the referenceid field.

Filtering posts from a large multi-dimentional array, PHP, Facebook API

I need help moving through the large array returned by the Facebook PHP SDK. I am trying to find all posts from the user, then also check if the post does/doesn't contain the 'link' key. I have read that it is inefficient to use the foreach loop on arrays of this size due to the copying of the 1MB+ of data to process it. How should I traverse through the information effectively?
The array is structured like this, where 'x' is the number of each post:
Array
(
[data] => Array
(
[x] => Array
(
[from] => Array
(
[name] => james
)
[message] => Thanks for the great interview!
[link] => http://example.com/link.html
[description] => Description here
[etc] => Various other keys possible
)
)
)
Then my current code looks like this where $feed is the array from the Facebook API:
for ($x=0, $y=0; $x<=1000, $y<=19; $x++) {
if (array_key_exists('james', $feed['data'][$x]['from']['name'])) {
if (!array_key_exists('link', $feed['data'][$x])) {
echo "<div>" . $feed['data'][$x]['message'] . "<hr>" . $feed['data'][$x]['description'] . "</div>";
$y++;
};
};
};
I have read about the various iterators but I wouldn't know which to use! Hope you can help me out, cheers, Joe
Speaking about foreach performance
and using array_key_exists in actual fact it's a non sense
imho it's far better like
foreach($feed['data'] as $post){
if($post['from']['name']==='youruser'){
//has user
}
if(isset($post['link'])){
//has link
}
}
put it in the cillosis way
and it should be faster.
You are correct in the fact that foreach can be slow when iterating over large arrays because by default it uses a copy of the value and like you mentioned, that copying can consume memory and take a bit of a time hit.
But, another way to use foreach is by reference which does not create a copy. It works with the original value. This means no matter what size the array is, it won't be placed into memory again. Here is an example of a foreach by reference as shared by another StackOverflow user:
$a = array('hello', 'world');
$asRef =& $a;
$ontime = 0;
foreach($asRef as $i => $v)
{
if (!$ontime++) $a = array('hash', 'the cat');
echo " $i: $v\n";
}
You have the option of using the ArrayIterator from the SPL which is written in C and is pretty fast. Just a quick example of how that would work:
// This would be your large facebook array
$big_array = array(1,2,3,...,10000,10001);
// Get the iterator object
$array_iterator = new ArrayIterator($big_array);
foreach($array_iterator as $item)
{
//Do something with $item here
}
I've not done any benchmarking but I would imagine passing the array by reference and using the ArrayIterator would probably be a good solution.
foreach doesn't always copy. when it does copy, it copies only the immediate data structure being iterated; it doesn't copy any values. for example, if you did
foreach ($arr['data'] as $k => $v) ....
if there were 100 sub elements (you abbreviated one as [x] ), then it would make an array, copy those 100 keys, but would not copy the values that the keys point to, the values being the sub arrays/trees. internally it just stores a pointer and has it point to the subarray's memory address, without copying.
I think you're making a big deal for nothing, as the amount of data that actually gets copied is very little. foreach is almost always very very fast...
if you want to glimpse, look at memory_get_usage() and memory_get_peak_usage() before and after your loop.

while(list($key, $value) = each($array)) vs. foreach($array as $key => $value)?

Recently I experienced this weird problem:
while(list($key, $value) = each($array))
was not listing all array values, where replacing it with...
foreach($array as $key => $value)
...worked perfectly.
And, I'm curious now.. what is the difference between those two?
Had you previously traversed the array? each() remembers its position in the array, so if you don't reset() it you can miss items.
reset($array);
while(list($key, $value) = each($array))
For what it's worth this method of array traversal is ancient and has been superseded by the more idiomatic foreach. I wouldn't use it unless you specifically want to take advantage of its one-item-at-a-time nature.
array each ( array &$array )
Return the current key and value pair from an array and advance the array cursor.
After each() has executed, the array cursor will be left on the next element of the array, or past the last element if it hits the end of the array. You have to use reset() if you want to traverse the array again using each.
(Source: PHP Manual)
Well, one difference is that each() will only work on arrays (well only work right). foreach will work on any object that implements the traversable interface (Which of course includes the built in array type).
There may be a micro-optimization in the foreach. Basically, foreach is equivilant to the following:
$array->rewind();
while ($array->valid()) {
$key = $array->key();
$value = $array->current();
// Do your code here
$array->next();
}
Whereas each basically does the following:
$return = $array->valid() ? array($array->key(), $array->current()) : false;
$array->next();
return $return;
So three lines are the same for both. They are both very similar. There may be some micro-optimizations in that each doesn't need to worry about the traversable interface... But that's going to be minor at best. But it's also going to be offset by doing the boolean cast and check in php code vs foreach's compiled C... Not to mention that in your while/each code, you're calling two language constructs and one function, whereas with foreach it's a single language construct...
Not to mention that foreach is MUCH more readable IMHO... So easier to read, and more flexible means that -to me- foreach is the clear winner. (that's not to say that each doesn't have its uses, but personally I've never needed it)...
Warning! Foreach creates a copy of the array so you cannot modify it while foreach is iterating over it. each() still has a purpose and can be very useful if you are doing live edits to an array while looping over it's elements and indexes.
// Foreach creates a copy
$array = [
"foo" => ['bar', 'baz'],
"bar" => ['foo'],
"baz" => ['bar'],
"batz" => ['end']
];
// while(list($i, $value) = each($array)) { // Try this next
foreach($array as $i => $value) {
print $i . "\n";
foreach($value as $index) {
unset($array[$index]);
}
}
print_r($array); // array('baz' => ['end'])
Both foreach and while will finish their loops and the array "$array" will be changed. However, the foreach loop didn't change while it was looping - so it still iterated over every element even though we had deleted them.
Update: This answer is not a mistake.
I thought this answer was pretty straight forward but it appears the majority of users here aren't able to appreciate the specific details I mention here.
Developers that have built applications using libdom (like removing elements) or other intensive map/list/dict filtering can attest to the importance of what I said here.
If you do not understand this answer it will bite you some day.
If you passed each an object to iterate over, the PHP manual warns that it may have unexpected results.
What exactly is in $array

Categories