tfburges Posted August 12, 2009 Share Posted August 12, 2009 I'll try to make this as quick and concise as possible. I have a multidimensional array created by a function that parses xml files. The array structure can be best described by the following example... Given this XML: <SomeParent xml="blahBlah"> <OneElement>1.0</OneElement> <MultipleElementsOfSameName>Some value</MultipleElementsOfSameName> <MultipleElementsOfSameName>Another value</MultipleElementsOfSameName> <MultipleElementsOfSameName name="someAttribute">Some value</MultipleElementsOfSameName> </SomeParent> The following array will be created: Array ( [someParent] => Array ( [_a] => Array ( [xml] => blahBlah ) [_c] => Array ( [OneElement] => Array ( [_v] => 1.0 ) [MultipleElementsOfSameName] => Array ( [0] => Array ( [_v] => Some value ) [1] => Array ( [_v] => Another value ) [2] => Array ( [_a] => Array ( [name] => someAttribute ) [_v] => Some value ) ) ) ) ) Note that when multiple elements of the same name are present, that array key is created with numeric sub keys. Now, I have functions that generate forms based on the array and I would like to modify the respective values in the multidimensional array when post data is present. I have a javascript function that allows the user to add any number of extra elements of the same name (if a certain input to the form generation function is set to true but that's irrelevant)... and the names of the inputs would be something like "MultipleElementsOfSameName_num_0", "MultipleElementsOfSameName_num_1", "MultipleElementsOfSameName_num_2", etc. as more are added. I also have a hidden input that specifies how many the user has added (which is theoretically infinite). So... I have a function that handles post data: (Note that the second if statement in this function is for handling if there was only one element of a name present before, the array will need to move the original element's data to a key of '0' under that name to follow the correct structure of multiple elements.) /* Quick function for handling post data; can handle any number of elements that have been added by the PHP/javascript "Add Another" functions */ // 08.09.2009 function handlePostData($name,&$storeStart,$storeDepth) { if ($_POST['AddMore_' . $name . '_num']) { $i = 0; $num = $_POST['AddMore_' . $name . '_num']; if ($_POST[$name] && $num > 0) { $copy = $storeStart; foreach ($storeStart as &$sub) { unset($sub); } $storeStart['0'] = $copy; $storeLocation = digDeep(&$storeStart['0'],$storeDepth); $storeLocation = $_POST[$name]; $i = 1; } while ($i <= $num) { if ($_POST[$name . '_num_' . $i]) { $storeStart[$i] = $copy; $storeLocation = digDeep(&$storeStart[$i],$storeDepth); $storeLocation = $_POST[$name . '_num_' . $i]; } $i++; } } else { if ($_POST[$name]) { $storeLocation = digDeep(&$storeStart,$storeDepth); $storeLocation = $_POST[$name]; } } } The digDeep function is what I use for ensuring data retrieval from the multidimensional array regardless of whether or not an element it is singular or multiple. It is as follows: /* This function "digs" into a multidimensional array and returns whatever it finds */ // 08.09.2009 function digDeep($start,$depth) { if (is_array($depth)) { foreach ($depth as &$dig) { $start = &$start[$dig]; } } else if ($depth != "" && $depth != 0 && $depth != false) { $start = &$start[$depth]; } return $start; } I just added the ampersands ("&") hoping that would modify the original array's value(s) because that's what I want to happen when data is posted. I'm beginning to think the best way to handle something like this is to redo the "digDeep" function and make it something like... function digDeep($start, $depth) { if (sizeof($depth) == 0) { return $start; } else if (sizeof($depth) == 1) { return start[$depth[0]]; } else if (sizeof($depth) == 2) { return start[$depth[0]][$depth[1]]; } // etc. } I've actually gotta cut this a bit short right now but hopefully this will be enough to point me in the right direction. Link to comment https://forums.phpfreaks.com/topic/170000-solved-function-for-navigatingmodifying-a-multidimensional-array/ Share on other sites More sharing options...
tfburges Posted August 13, 2009 Author Share Posted August 13, 2009 Now that I'm back... I reviewed what I posted and it may not be clear enough... but I think I included all relevant information. If something is unclear let me know. It looks like my problem is ampersand usage. I'm not sure if it's possible to use it in a for loop like I did but I don't see why not. I've always been unsure when and where to place the ampersands when I want to modify the original variable... I'll read up on it again but in the mean time, I'm pretty sure that's what my problem is if someone experienced can help. Link to comment https://forums.phpfreaks.com/topic/170000-solved-function-for-navigatingmodifying-a-multidimensional-array/#findComment-896853 Share on other sites More sharing options...
tfburges Posted August 13, 2009 Author Share Posted August 13, 2009 I tried the following with various similar combinations of ampersand usage and to no avail... /* Quick function for handling post data; can handle any number of elements that have been added by the PHP/javascript "Add Another" functions */ // 08.09.2009 function handlePostData($name,&$storeStart,$storeDepth) { if ($_POST['AddMore_' . $name . '_num']) { $i = 0; $num = $_POST['AddMore_' . $name . '_num']; if ($_POST[$name] && $num > 0) { $copy = $storeStart; foreach ($storeStart as &$sub) { unset($sub); } $storeStart['0'] = $copy; $storeLocation = &digDeep($storeStart['0'],$storeDepth); $storeLocation = $_POST[$name]; $i = 1; } while ($i <= $num) { if ($_POST[$name . '_num_' . $i]) { $storeStart[$i] = $copy; $storeLocation = &digDeep($storeStart[$i],$storeDepth); $storeLocation = $_POST[$name . '_num_' . $i]; } $i++; } } else { if ($_POST[$name]) { $storeLocation = &digDeep($storeStart,$storeDepth); $storeLocation = $_POST[$name]; } } } /* This function "digs" into a multidimensional array and returns whatever it finds */ // 08.09.2009 function digDeep($start,$depth) { if (is_array($depth)) { /*foreach ($depth as $dig) { $start = $start[$dig]; }*/ if (sizeof($depth) == 1) { $output = &$start[$depth[0]]; } else if (sizeof($depth) == 2) { $output = &$start[$depth[0]][$depth[1]]; } else if (sizeof($depth) == 3) { $output = &$start[$depth[0]][$depth[1]][$depth[2]]; } else if (sizeof($depth) == 4) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]]; } else if (sizeof($depth) == 5) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]]; } else if (sizeof($depth) == 6) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]]; } else if (sizeof($depth) == 7) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]]; } else if (sizeof($depth) == { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]]; } else if (sizeof($depth) == 9) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]][$depth[8]]; } else if (sizeof($depth) == 10) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]][$depth[8]][$depth[9]]; } else if (sizeof($depth) == 11) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]][$depth[8]][$depth[9]][$depth[10]]; } else if (sizeof($depth) == 12) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]][$depth[8]][$depth[9]][$depth[10]][$depth[11]]; } else if (sizeof($depth) == 13) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]][$depth[8]][$depth[9]][$depth[10]][$depth[11]][$depth[12]]; } else if (sizeof($depth) == 14) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]][$depth[8]][$depth[9]][$depth[10]][$depth[11]][$depth[12]][$depth[13]]; } else if (sizeof($depth) == 15) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]][$depth[8]][$depth[9]][$depth[10]][$depth[11]][$depth[12]][$depth[13]][$depth[14]]; } else { $output = array('Array size of depth cannot be greater than 15.'); } } else if ($depth != "" && $depth != 0 && $depth != false) { $output = &$start[$depth]; } else { $output = &$start; } return $output; } Link to comment https://forums.phpfreaks.com/topic/170000-solved-function-for-navigatingmodifying-a-multidimensional-array/#findComment-896931 Share on other sites More sharing options...
tfburges Posted August 13, 2009 Author Share Posted August 13, 2009 Hmmm I still may not be clear. This example should help... Suppose there is only 1 AssetType, and so following variable exists: $_SESSION['configWizard']['AssetType']['_c']['Model']['_v'] (Model is a child of AssetType and has a value; hence, "_c" and "_v"... remember, this array structure comes from a large XML file.) And in the config wizard, the user creates at least one other AssetType... So to account for more than one key of the same name, the original AssetType must be moved to the following array like so: $_SESSION['configWizard']['AssetType']['_c']['Model']['_v'] --> $_SESSION['configWizard']['AssetType']['0']['_c']['Model']['_v'] ...so that any additional AssetTypes can be added whose structure will look something like: $_SESSION['configWizard']['AssetType']['1']['_c']['Model']['_v'] $_SESSION['configWizard']['AssetType']['2']['_c']['Could'][_c]['Be']['_v'] $_SESSION['configWizard']['AssetType']['3']['_c']['Anything']['_v'] Now, I've added a lot of comments/questions to my code to help explain what I'm trying to do... so please read: function handlePostData($name,&$storeStart,$storeDepth) { // name is simply the name of the input text field that is used to modify a particular key // storeStart should be the starting array to be modified, i.e. $_SESSION['configWizard']['etc'] // and the ampersand is before storeStart so that whatever variable passed is modified, not a copy // storeDepth is an array like: array('_c','Model','_v') so that the function can access // the correct key structure regardless of whether or not it is something like... // $_SESSION['configWizard']['AssetType']['_c']['Model']['_v'] // versus // $_SESSION['configWizard']['AssetType']['0']['_c']['Model']['_v'] if ($_POST['AddMore_' . $name . '_num']) { // this post variable is a hidden input that counts the number of extra elements // of the same key that were added $i = 0; $num = $_POST['AddMore_' . $name . '_num']; if ($_POST[$name] && $num > 0) { // if just post[name], meaning there was only 1 to begin with // (since if there was more than 1 to begin with, the post variable would be... // ...post[name_num_0],post[name_num_1],etc.) // and another element of same key was added (i.e., num > 0) $copy = $storeStart; // store a copy the data within the single key structure... // because... // $_SESSION['configWizard']['AssetType'] // ...needs to be copied to... // $_SESSION['configWizard']['AssetType']['0'] foreach ($storeStart as &$sub) { unset($sub); // since the entire structure under the starting position will be moved // everything under the starting position needs to be unset } $storeStart['0'] = $copy; // $_SESSION['configWizard']['AssetType'] // ...should now copied be to... // $_SESSION['configWizard']['AssetType']['0'] $storeLocation = &digDeep($storeStart['0'],$storeDepth); // the storeLocation should be a specific key structure beneath the newly moved/created array // the digDeep function should return the actual $_SESSION variable and not a copy $storeLocation = $_POST[$name]; // the posted data should replace the data in that particular location of memory $i = 1; // set the index to 1 so that it starts at 1 now since 0 is taken care of } while ($i <= $num) { if ($_POST[$name . '_num_' . $i]) { // each element added in the config wizard should have an input similar to... // name_num_0, name_num_1, etc. $storeLocation = &digDeep($storeStart[$i],$storeDepth); // the store location should become something like... // $_SESSION['configWizard']['AssetType']['1']['_c']['Model']['_v'] // then... // $_SESSION['configWizard']['AssetType']['2']['_c']['Model']['_v'] // for each one added/present // etc. $storeLocation = $_POST[$name . '_num_' . $i]; // store the respective posted data in memory } $i++; } } else { // there was only 1 element of a particular key and no extra elements were added, so... if ($_POST[$name]) { // make sure something was posted $storeLocation = &digDeep($storeStart,$storeDepth); // the storeLocation would still need to point to the correct address in memory $storeLocation = $_POST[$name]; } } } Now... I've been testing with the simplest case (where there was only 1 element of a particular key and no extra elements were added)... so the problem must lie within my digDeep function and/or the ampersand usage in the handlePostData function. Here's the digDeep function again: function digDeep(&$start,$depth) { // any changes/references to start should be direct, not a copy if (is_array($depth)) { // I made it this ridiculous if/else statement just to work out the kinks in my ampersand usage... // It used to be a for loop. if (sizeof($depth) == 1) { $output = &$start[$depth[0]]; } else if (sizeof($depth) == 2) { $output = &$start[$depth[0]][$depth[1]]; } else if (sizeof($depth) == 3) { $output = &$start[$depth[0]][$depth[1]][$depth[2]]; } else if (sizeof($depth) == 4) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]]; } else if (sizeof($depth) == 5) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]]; } else if (sizeof($depth) == 6) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]]; } else if (sizeof($depth) == 7) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]]; } else if (sizeof($depth) == { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]]; } else if (sizeof($depth) == 9) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]][$depth[8]]; } else if (sizeof($depth) == 10) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]][$depth[8]][$depth[9]]; } else if (sizeof($depth) == 11) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]][$depth[8]][$depth[9]][$depth[10]]; } else if (sizeof($depth) == 12) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]][$depth[8]][$depth[9]][$depth[10]][$depth[11]]; } else if (sizeof($depth) == 13) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]][$depth[8]][$depth[9]][$depth[10]][$depth[11]][$depth[12]]; } else if (sizeof($depth) == 14) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]][$depth[8]][$depth[9]][$depth[10]][$depth[11]][$depth[12]][$depth[13]]; } else if (sizeof($depth) == 15) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]][$depth[8]][$depth[9]][$depth[10]][$depth[11]][$depth[12]][$depth[13]][$depth[14]]; } else { $output = array('Array size of depth cannot be greater than 15.'); } } else if ($depth != "" && $depth != 0 && $depth != false) { $output = &$start[$depth]; } else { $output = &$start; } return $output; // the output returned SHOULD be a direct reference to the location in memory, not a copy // ...but it does not seem to be working that way no matter what I do. } Also, here is an example of simple usage (testing the case of just 1 element, no extra): In theory, it may either be... handlePostData('Model',$_SESSION['configWizard']['AssetType'],array('_c','Model','_v')); ...or... handlePostData('Model',$_SESSION['configWizard']['AssetType']['_c']['Model'],false); ...but neither work. It MUST be my use of ampersands but I just can't figure it out! Do you see what the problem is? And does anyone know how to solve it? Link to comment https://forums.phpfreaks.com/topic/170000-solved-function-for-navigatingmodifying-a-multidimensional-array/#findComment-897017 Share on other sites More sharing options...
tfburges Posted August 13, 2009 Author Share Posted August 13, 2009 Ahhhhh I figured it out! The problem was that I needed an ampersand before the name of the function, digDeep, so that PHP knew to return a reference (AKA pointer in C/C++). It looks like PHP isn't so different from C/C++ after all. This is what I had to do: (Note the placement of the ampersands before the variables and before the digDeep function.) /* This function "digs" into a multidimensional array and returns whatever it finds */ // 08.09.2009; 08.13.2009 function &digDeep($start,$depth) { if (is_array($depth)) { if (sizeof($depth) == 1) { $output = &$start[$depth[0]]; } else if (sizeof($depth) == 2) { $output = &$start[$depth[0]][$depth[1]]; } else if (sizeof($depth) == 3) { $output = &$start[$depth[0]][$depth[1]][$depth[2]]; } else if (sizeof($depth) == 4) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]]; } else if (sizeof($depth) == 5) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]]; } else if (sizeof($depth) == 6) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]]; } else if (sizeof($depth) == 7) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]]; } else if (sizeof($depth) == { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]]; } else if (sizeof($depth) == 9) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]][$depth[8]]; } else if (sizeof($depth) == 10) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]][$depth[8]][$depth[9]]; } else if (sizeof($depth) == 11) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]][$depth[8]][$depth[9]][$depth[10]]; } else if (sizeof($depth) == 12) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]][$depth[8]][$depth[9]][$depth[10]][$depth[11]]; } else if (sizeof($depth) == 13) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]][$depth[8]][$depth[9]][$depth[10]][$depth[11]][$depth[12]]; } else if (sizeof($depth) == 14) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]][$depth[8]][$depth[9]][$depth[10]][$depth[11]][$depth[12]][$depth[13]]; } else if (sizeof($depth) == 15) { $output = &$start[$depth[0]][$depth[1]][$depth[2]][$depth[3]][$depth[4]][$depth[5]][$depth[6]][$depth[7]][$depth[8]][$depth[9]][$depth[10]][$depth[11]][$depth[12]][$depth[13]][$depth[14]]; } else { $output = array('Array size of depth cannot be greater than 15.'); } } else if ($depth != "" && $depth != 0 && $depth != false) { $output = &$start[$depth]; } else { $output = &$start; } return $output; } /* Quick function for handling post data; can handle any number of elements that have been added by the PHP/javascript "Add Another" functions */ // 08.09.2009; 08.13.2009 function handlePostData($name,&$storeStart,$storeDepth) { if ($_POST['AddAnother_' . $name . '_num']) { $i = 0; $num = $_POST['AddAnother_' . $name . '_num']; if ($_POST[$name] && $num > 0) { $copy = $storeStart; foreach ($storeStart as &$sub) { unset($sub); } $storeStart['0'] = $copy; $storeLocation = &digDeep(&$storeStart['0'],$storeDepth); $storeLocation = $_POST[$name]; $i = 1; } while ($i <= $num) { if ($_POST[$name . '_num_' . $i]) { $storeLocation = &digDeep(&$storeStart[$i],$storeDepth); $storeLocation = $_POST[$name . '_num_' . $i]; } $i++; } } else { if ($_POST[$name]) { $storeLocation = &digDeep(&$storeStart,$storeDepth); $storeLocation = $_POST[$name]; } } } Link to comment https://forums.phpfreaks.com/topic/170000-solved-function-for-navigatingmodifying-a-multidimensional-array/#findComment-897650 Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.