The line below commented GOAL creates an error. The error is not displayed (just get a white screen) and I do not have access to php.ini to change the settings. I'm quite sure the error is something along the lines of "can not use [] for reading".
How can I get around this? The keys must be preserved and that doesn't seem possible with array_push.
foreach ($invention_values as $value)
{
if( array_key_exists($value->field_name, $array) )
{
//GOAL but creates error: $array[$value->field_name][] = $value->field_value;
//works but only with numeric keys
array_push($array, $value);
}
else $array[$value->field_name] = $value;
}
EDIT: code
EDIT2: Actually I think the error is cause I'm dealing with an object an not an array. What is the object equivalent of
$array[$value->field_name][] = $value ?
Your $array[$value->field_name] is empty, so you can't use [] on it. To initialize it as an array, you have to do the following:
if(!array_key_exists($value->field_name, $array) ){
$array[$value->field_name] = array();
}
$array[$value->field_name][] = $value->field_value;
It contradicts with what you have in your last line, so you have to decide, do you want $array[$value->field_name] be an array or scalar value.
Related
So $tr['tree'] is an array. $dic is an array stored as key values. I want to add the key source to that those arrays. It looks like the following code doesn't work as expected as I'm guessing $dic is a new instance of the array object inside $tr['tree'].
foreach($tr['tree'] as $dic){
$dic['source'] = $tr['source']." > ".$dic['name'];
}
Note, I'm coming from python where this would work brilliantly. So how would I do this in PHP?
foreach() creates copies of the items you're looping on, so $dic in the loop is detached from the array. If you want to modify the parent array, the safe method is to use:
foreach($array as $key => $value) {
$array[$key] = $new_value;
}
You could use a reference:
foreach($array as &$value) {
^---
$value = $new_value;
}
but that can lead to stupidly-hard-to-find bugs later. $value will REMAIN a reference after the foreach terminates. If you re-use that variable name later on for other stuff, you'll be modifying the array, because the var still points at it.
I would like to pass in an array that contains a list of directories to scan. I want to iterate over each directory and push its content into another array that I will print out, but for some reason my code is not working. The directories exist and the path is correct. I think it has something to do with how I'm using foreach.
These are the errors I'm getting:
Notice: Undefined index: C:\Users\john\Desktop\files\images\ in
C:\xampp\htdocs\test.php on line 6
Warning: scandir(): Directory name cannot be empty in
C:\xampp\htdocs\test.php on line 6
This is the code:
function test($dir = []) {
foreach($dir as $bar) {
$list = [];
array_push($list, scandir($dir[$bar]));
}
print_r($list);
}
test(["C:\Users\john\Desktop\files\images\\", "C:\Users\john\Desktop\files\images\autumn\\"]);
If anyone can think of a simpler way to do this, please don't hesitate to tell me.
You're on the right track. There are a few changes you need to make though.
function test($dir = []) {
$list = [];
foreach($dir as $bar) {
$list[] = scandir($bar);
}
print_r($list);
}
As noted by #BrianPoole you need to move the $list out of the foreach loop. By having it in the loop, the array is reset with each iteration, resulting in the final array having one element.
In addition, the foreach loop as explained above by #TimCooper does not operate the same as in JavaScript. If you really want to access the keys, you can use the following syntax:
foreach($dir as $key => $bar)
You would then use either $dir[$key] or $bar to access the directory value.
Finally, array_push is an additional function call that in your case is not needed. By simply adding [] PHP will push the new value onto the end of the array.
function test($dir) {
// DEFINE LIST OUT SIDE OF LOOP
$list = array();
// Run checks
if(count($dir) > 0) {
// Loop Through Directory
foreach($dir as $directory) {
// Push into list
array_push($list, array("scanned"=>$directory, "contents" => scandir($directory)));
}
}else {
// If no directories are passed return array with error
$list = array(
"error" => 1,
"message" => "No directories where passed into test()",
);
}
print_r($list);
}
This is how I would do it. It provides a couple checks and sets up the data so you can se it a bit more clear.
i've just reworked my recursion detection algorithm in my pet project dump_r()
https://github.com/leeoniya/dump_r.php
detecting object recursion is not too difficult - you use spl_object_hash() to get the unique internal id of the object instance, store it in a dict and compare against it while dumping other nodes.
for array recursion detection, i'm a bit puzzled, i have not found anything helpful. php itself is able to identify recursion, though it seems to do it one cycle too late. EDIT: nvm, it occurs where it needs to :)
$arr = array();
$arr[] = array(&$arr);
print_r($arr);
does it have to resort to keeping track of everything in the recursion stack and do shallow comparisons against every other array element?
any help would be appreciated,
thanks!
Because of PHP's call-by-value mechanism, the only solution I see here is to iterate the array by reference, and set an arbitrary value in it, which you later check if it exists to find out if you were there before:
function iterate_array(&$arr){
if(!is_array($arr)){
print $arr;
return;
}
// if this key is present, it means you already walked this array
if(isset($arr['__been_here'])){
print 'RECURSION';
return;
}
$arr['__been_here'] = true;
foreach($arr as $key => &$value){
// print your values here, or do your stuff
if($key !== '__been_here'){
if(is_array($value)){
iterate_array($value);
}
print $value;
}
}
// you need to unset it when done because you're working with a reference...
unset($arr['__been_here']);
}
You could wrap this function into another function that accepts values instead of references, but then you would get the RECURSION notice from the 2nd level on. I think print_r does the same too.
Someone will correct me if I am wrong, but PHP is actually detecting recursion at the right moment. Your assignation simply creates the additional cycle. The example should be:
$arr = array();
$arr = array(&$arr);
Which will result in
array(1) { [0]=> &array(1) { [0]=> *RECURSION* } }
As expected.
Well, I got a bit curious myself how to detect recursion and I started to Google. I found this article http://noteslog.com/post/detecting-recursive-dependencies-in-php-composite-values/ and this solution:
function hasRecursiveDependency($value)
{
//if PHP detects recursion in a $value, then a printed $value
//will contain at least one match for the pattern /\*RECURSION\*/
$printed = print_r($value, true);
$recursionMetaUser = preg_match_all('#\*RECURSION\*#', $printed, $matches);
if ($recursionMetaUser == 0)
{
return false;
}
//if PHP detects recursion in a $value, then a serialized $value
//will contain matches for the pattern /\*RECURSION\*/ never because
//of metadata of the serialized $value, but only because of user data
$serialized = serialize($value);
$recursionUser = preg_match_all('#\*RECURSION\*#', $serialized, $matches);
//all the matches that are user data instead of metadata of the
//printed $value must be ignored
$result = $recursionMetaUser > $recursionUser;
return $result;
}
I'm trying to pass 3 parameter to a script, where the 3rd parameter $_GET['value3'] is supposed to be an array
$_GET['value1']
$_GET['value2']
$_GET['value3'] //an array of items
I'm calling the script like this: (notice my syntax for value3, I'm not sure it's correct)
http://localhost/test.php?value1=test1&value2=test2&value3=[the, array, values]
I then use a foreach to hopefully loop through the third parameter value3 which is the array
//process the first input $_GET['value1']
//process the second input $_GET['value2']
//process the third input $_GET['value3'] which is the array
foreach($_GET['value3'] as $arrayitem){
echo $arrayitem;
}
but I get the error Invalid argument supplied for foreach()
I'm not sure if my methodology is correct. Can some clarify how you'd go about doing the sort of thing
There is no such thing as "passing an array as a URL parameter" (or a form value, for that matter, because this is the same thing). These are strings, and anything that happens to them beyond that is magic that has been built into your application server, and therefore it is non-portable.
PHP happens to support the &value3[]=the&value3[]=array&value3[]=values notation to automagically create $_GET['value3'] as an array for you, but this is special to PHP and does not necessarily work elsewhere.
You can also be straight-forward and go for a cleaner URL, like this: value3=the,array,values, and then use explode(',', $_GET['value3']) in your PHP script to create an array. Of course this implies that your separator char cannot be part of the value.
To unambiguously transport structured data over HTTP, use a format that has been made for the purpose (namely: JSON) and then use json_decode() on the PHP side.
try
http://localhost/test.php?value1=test1&value2=test2&value3[]=the&value3[]=array&value3[]=values
For arrays you need to pass the query parameters as
value3[]=abc&value3[]=pqr&value3[]=xyz
You can cast the name of the index in the string too
?value1[a]=test1a&value1[b]=test1b&value2[c][]=test3a&value2[c][]=test3b
would be
$_GET['value1']['a'] = test1a
$_GET['value1']['b'] = test1b
$_GET['value2']['c'] = array( 'test3a', 'test3b' );
http://php.net/manual/en/reserved.variables.get.php
Check out the above link..
You will see how the GET method is implemented.
What happens is that the URL is taken, it is delimited using '&' and then they are added as a key-value pair.
public function fixGet($args) {
if(count($_GET) > 0) {
if(!empty($args)) {
$lastkey = "";
$pairs = explode("&",$args);
foreach($pairs as $pair) {
if(strpos($pair,":") !== false) {
list($key,$value) = explode(":",$pair);
unset($_GET[$key]);
$lastkey = "&$key$value";
} elseif(strpos($pair,"=") === false)
unset($_GET[$pair]);
else {
list($key, $value) = explode("=",$pair);
$_GET[$key] = $value;
}
}
}
return "?".((count($_GET) > 0)?http_build_query($_GET).$lastkey:"");
}
Since, they are added as a key-value pair you can't pass array's in the GET method...
The following would also work:
http://localhost/test.php?value3[]=the&value3[]=array&value3[]=values
A more advanced approach would be to serialize the PHP array and print it in your link:
http://localhost/test.php?value3=a:3:{i:0;s:3:"the";i:1;s:5:"array";i:2;s:6:"values";}
would, essentially, also work.
How can you do this? My code seen here doesn't work
for($i=0;i<count($cond);$i++){
$cond[$i] = $cond[$i][0];
}
It can be as simple as this:
$array = array_map('reset', $array);
There could be problems if the source array isn't numerically index. Try this instead:
$destinationArray = array();
for ($sourceArray as $key=>$value) {
$destinationArray[] = $value[0]; //you may want to use a different index than '0'
}
// Make sure you have your first array initialised here!
$array2 = array();
foreach ($array AS $item)
{
$array2[] = $item[0];
}
Assuming you want to have the same variable name afterwards, you can re-assign the new array back to the old one.
$array = $array2;
unset($array2); // Not needed, but helps with keeping memory down
Also, you might be able to, dependant on what is in the array, do something like.
$array = array_merge(array_values($array));
As previously stated, your code will not work properly in various situation.
Try to initialize your array with this values:
$cond = array(5=>array('4','3'),9=>array('3','4'));
A solution, to me better readable also is the following code:
//explain what to do to every single line of the 2d array
function reduceRowToFirstItem($x) { return $x[0]; }
// apply the trasnformation to the array
$a=array_map('reduceRowTofirstItem',$cond);
You can read the reference for array map for a thorough explanation.
You can opt also for a slight variation using array_walk (it operate on the array "in place"). Note that the function doesn't return a value and that his parameter is passed by reference.
function reduceToFirstItem(&$x) { $x=$x[0]; }
array_walk($cond, 'reduceToFirstItem');
That should work. Why does it not work? what error message do you get?
This is the code I would use:
$inArr;//This is the 2D array
$outArr = array();
for($i=0;$i<count($inArr);$i++){
$outArr[$i] = $inArr[$i][0];
}