PHP referencing variables in an array as foreach keys - php

I know my title is quite ambivalent but if you bear me, you'll find it is not so bad :P
I have a class method that gets quite different database fields in any order and builds an array based on those fields (each key adds another level into the array).
Now, that's the easy part. I also have a correction function that unifies the e.g. costs by some demographic data. The problem is that I need to address the right level in the correction formula.
I try to make an example:
I ask fields A,year,B,C,D and my correction formula for D depends on the year and C. I have formalized so that C and D are always the last ones to list but the problem is that how do I address the year so that I could get out an answer like [A][year][B]=function(year,c,d). The fields are in an array ($retr['fields']=array("A","year","B","C") (the result D comes automatically)
I tried to use foreach like
$retr['fields']=array("A","year","B","C")
$temp=get_data($retr);
foreach($temp as $${$retr['fields'][0]} => $yd)
foreach ($yd as $${$retr['fields'][1]} => $cd) {
$output[$${$retr['fields'][0]}][$${$retr['fields'][1]}]=0;
foreach ($cd as $a => $v)
$output[$${$retr['fields'][0]}][$${$retr['fields'][1]}]+=$v*$act[$year][$a]
and so on, but it seems that one can't use a variable variable as a key in foreach (or then I have got the syntax wrong). As now it just says that "Undefined variable: year"
Do you have any ideas how to express what I need?

Well I solved it, or rather not solved but programmed around.
For each foreach I checked the corresponding field and if it was year, I made a variable with value of current foreach key and referenced it with $$variable.
Like this:
$temp=get_data($retr);
foreach($temp as $varA => $yd) {
if ($retr[0]=="year")
$year_var=varA;
.
.
.
$output[$varA][$varB]+=$v*$act[$$year_var][$a]
I still would have preferred a cleaner solution but given my timeframe (or rather the loss of it) this should suffice.
I'm still interested in the "perfect solution"(TM)
Thx anyway :)

It's kind of hard to understand your structure, but it appears you're fetching some data items and then categorize them into tree-like structure.
In this case, even though a particular attribute (e.g. year) appears on some upper level it's still, essentially, an attribute of the data item itself, so keep it as such: convert the "value" into a non-scalar (either object or hash). Then you would be able to work with those attributes without referencing outer loop values (and without resorting to variable variables):
foreach($arr as $subarr) {
foreach ($subarr as $subsubarr) {
// ... and so on
foreach ($lastlevel as $value) {
$adjusted = correctionFunc($value->data, $value->year, $value->somethingelse); // assuming value is an object
}
}
}

Related

Overwrite the original array values in PHP in nested loop

Cutting out some of the code on the innermost foreach, I'm trying to change HERE to make it so that it alters the original value. I want to pass a pointer basically and alter it. I was able to kind of do this with the &$ keyword in the foreach but (as the docs state) it results in some buggy behavior and I'm trying to do it the way they, and others on SO suggest. The problem is all the examples I find are for a single foreach, not for nested.
The following code loops properly but when I get to the HERE it doesn't actually alter the original value. Also worth mentioning that $sources could be an array of arrays (by index) or an array of key values. This looping code seems to iterate over both fine though, just not overriding the original value of $sources
fwiw, on top of the &$ I also tried:
$sources[$sourceKey][$rowKey][$cellKey] = $date->format('m/d/Y');
Which $sources[$sourceKey][$rowKey][$cellKey] returns the right value if I print it but it still doesn't overwrite the original array.
function convertDates($sources) {
foreach($sources as $sourceKey => $sourceValue){
foreach ($sourceValue as $rowKey => $rowValue) {
foreach ($rowValue as $cellKey => $cellValue) {
HERE = $date->format('m/d/Y');
}
}
}
}
I never could get this to work correctly since there were two formats this loop could get (JSON encoded object and an array). Making it work for both was much harder than just doing it in JavaScript so instead of modifying on the server I format the data how I want client side and send it up. This formatting is purely presentational and for personal use so if someone were to put in a debugger and change the code to send a different format thats fine and there's no security issues.
So in the end, this code was rewritten in JS and since JS handles arrays and objects using the same pointers the above issue wasn't an issue any longer.

Assign array value to a field

I am working with migration and I am migrating taxonomy terms that the document has been tagged with. The terms are in the document are separated by commas. so far I have managed to separate each term and place it into an array like so:
public function prepareRow($row) {
$terms = explode(",", $row->np_tax_terms);
foreach ($terms as $key => $value) {
$terms[$key] = trim($value);
}
var_dump($terms);
exit;
}
This gives me the following result when I dump it in the terminal:
array(2) {
[0]=>
string(7) "Smoking"
[1]=>
string(23) "Not Smoking"
}
Now I have two fields field_one and field_two and I want to place the value 0 of the array into field_one and value 1 into field_two
e.g
field_one=[0]$terms;
I know this isn't correct and I'm not sure how to do this part. Any suggestions on how to do this please?
If you are only looking to store the string value of the taxonomy term into a different field of a node, then the following code should do the trick:
$node->field_one['und'][0]['value'] = $terms[0];
$node->field_two['und'][0]['value'] = $terms[1];
node_save($node);
Note you will need to load the node first, if you need help with that, comment here and will update my answer.
You are asking specifically about ArrayList and HashMap, but I think to fully understand what is going on you have to understand the Collections framework. So an ArrayList implements the List interface and a HashMap implements the Map interface.
List:
An ordered collection (also known as a sequence). The user of this interface has precise control over where in the list each element is inserted. The user can access elements by their integer index (position in the list), and search for elements in the list.
Map:
An object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most one value.
So as other answers have discussed, the list interface (ArrayList) is an ordered collection of objects that you access using an index, much like an array (well in the case of ArrayList, as the name suggests, it is just an array in the background, but a lot of the details of dealing with the array are handled for you). You would use an ArrayList when you want to keep things in sorted order (the order they are added, or indeed the position within the list that you specify when you add the object).
A Map on the other hand takes one object and uses that as a key (index) to another object (the value). So lets say you have objects which have unique IDs, and you know you are going to want to access these objects by ID at some point, the Map will make this very easy on you (and quicker/more efficient). The HashMap implementation uses the hash value of the key object to locate where it is stored, so there is no guarentee of the order of the values anymore.
You might like to try:
list($field_one, $field_two) = prepareRow($row);
The list function maps entries in an array (in order) to the variables passed by reference.
This is a little fragile, but should work so long as you know you'll have at least two items in your prepareRow result.

drupal--why $node->taxonomy is an array

someone wrote this code.
foreach ($node->taxonomy as $term) {
$tids[] = 't.tid = %d';
$args[] = $term->tid;
}
how he knows that in foreach "$node->taxonomy" is an array? and when i loop it,
foreach ($node->taxonomy as $term) {
}
the output that i get will be the $term's value. i don't know how it is change into the 't.tid = %d' and $term->tid. thank you.
In Drupal-related code, a $node is almost always an object produced by the node_load() function. Since every module has the opportunity to add its own properties to this object, it's very hard to find a central documentation of these properties.
By experience and by variable inspection, seasoned Drupal developers know that when set $node->taxonomy is always an array of term object (as returned by the taxonomy_get_term() function) indexed by their respective ids (named tids, for Term ID). This array is set by the taxonomy_nodeapi() function when $op == 'load' and is produced by the taxonomy_get_terms() function.
The question give little information but we can guess that the loop is meant to build two arrays used to generate a database query that filter on the tid column matching those of the $node object. Because the terms' data is already stored in the items of $node->taxonomy, let's hope that this query is not used to re-load the terms to display some of their name and/or description. Collecting 't.tid = %d' is probably a bad idea, the query would be better build with a single "tid in (". db_placeholder($args) .")" WHERE clause after collecting all the tids in $args.
The question is very unclear. All Items under the node object are arrays. You can check it yourself bu using:
print_r($node);
die;
Or using any PHP debugger.
for the foreach, It is very simple foreach... I don't understand what is the problem with that.
t.tid is simply an SQL query. %d is a placeholder for $args[], which consists of $term->tid. It's like this structure: PDO connections.

PHP scope question

I'm trying to look through an array of records (staff members), in this loop, I call a function which returns another array of records (appointments for each staff member).
foreach($staffmembers as $staffmember)
{
$staffmember['appointments'] = get_staffmember_appointments_for_day($staffmember);
// print_r($staffmember['appointments'] works fine
}
This is working OK, however, later on in the script, I need to loop through the records again, this time making use of the appointment arrays, however they are unavailable.
foreach ($staffmembers as $staffmember)
{
//do some other stuff
//print_r($staffmember['appointments'] no longer does anything
}
Normally, I would perform the function from the first loop, within the second, however this loop is already nested within two others, which would cause the same sql query to be run 168 times.
Can anyone suggest a workaround?
Any advice would be greatly appreciated.
Thanks
foreach iterates over a copy of the array. If you want to change the value, you need to reference it:
foreach($staffmembers as &$staffmember) // <-- note the &
{
$staffmember['appointments'] = get_staffmember_appointments_for_day($staffmember);
// print_r($staffmember['appointments'] works fine
}
From the documentation:
Note: Unless the array is referenced, foreach operates on a copy of the specified array and not the array itself. foreach has some side effects on the array pointer. Don't rely on the array pointer during or after the foreach without resetting it.
and
As of PHP 5, you can easily modify array's elements by preceding $value with &. This will assign reference instead of copying the value.

PHP Compare Two Arrays?

I'm trying to compare two entries in a database, so when a user makes a change, I can fetch both database entries and compare them to see what the user changed, so I would have an output similar to:
User changed $fieldName from $originalValue to $newValue
I've looked into this and came across array_diff but it doesn't give me the output format I need.
Before I go ahead and write a function that does this, and returns it as a nice $mtextFormatDifferenceString, can anyone point me in the direction of a solution that already does this?
I don't want to re-invent the wheel..
Since you require "from $originalValue to $newValue", I would go ahead and select the two rows, put them in assoc arrays, then foreach through the keys, saving the ones that aren't equal. Kind of like:
$fields = array_keys($row1);
$changedFields = array();
foreach ($fields as $field) {
if ($row1[$field] != $row2[$field]) {
$changedFields[] = $field;
}
}
I realize you were asking about the existence of pre-built wheels but I felt the solution was pretty simple.
?>
Although you didn't define what format you needed, but well-known diff algorithm is probably for you. Google for PHP diff algorithm and you'll find some suggestions I am sure.
You could get the changed values ($newValue) with array_diff_assoc and then just use the keys ($fieldName) to find the original value $originalValue and output it in anyformat you want

Categories