PHP - Loop an array where only some keys are set explicitely - php

I have the following array
$a = ["one", "dos" => "two", "three"];
As you see the second element has the key for his value set explicitely, but the other 2 items do not.
I want to loop through the array, but do something different, depending if the key for that item was set explicitly or not. Kinda like this:
foreach($a as $value){
if( has_explicit_key($value) )
// Do something
else
// Do other stuff
}
How can I achieve this?
PS: I guess I could check if the key is an integer, but if the key is set explicitly as an integer, that would not work, right?

try this
foreach($a as $key=>$value){
if( is_int($key) )
// Do something
else
// Do other stuff
}
this is the closest approach since keys are usually, 0,1,2......

In your specific case, you can exploit the fact that elements without explicit string keys automatically receive integer indexes:
$a = ["one", "dos" => "two", "three"];
foreach ($a as $k => $v) {
if (is_int($k)) {
// Do something
} else {
// Do other stuff
}
}
If you allow for the explicit keys to be scalars other than strings (integer, float, boolean, etc), then there is no way (at run-time) to distinguish between non-string keys supplied by the user and integer keys filled in by the parser. Specifically, refer to the PHP source function zend_ast_add_array_element. In that function, when the key is not explicitly given (offset IS_UNDEF), then PHP assigns one with zend_hash_next_index_insert and records no bookkeeping note of that fact.
Now, if you don't mind, and are capable of statically analyzing the data structure, just tokenize or parse the PHP code and see if T_DOUBLE_ARROW precedes the array value. This is probably not worth the effort and only works on static code.

You can loop through the array using
foreach($a as $key => $value) {
/* stuff */
}
To check if the key has been set explicitly can probably only be done by checking if the key is numerical (PHP will assign numerical keys to values without any keys in arrays).
Of course this means that you won't be able to detect a key that was set explicitly and is numeric.
So unless there's some function (which I'm unaware of) this would be the only way.

Related

Search for dynamic key values in foreach loop in php

I feel like i'm missing something quite simple. What are some of the best ways to iterate through combinations of $key names -- doing something different for each-- in a php foreach loop?
I have a number of values in an array with key values that follow the same naming format.
Example:
$rec_items['title3'] = implode($meta['title3']);
$rec_items['title4'] = implode($meta['title4']);
$rec_items['title5'] = implode($meta['title5']);
The $rec_items array also contains other values that do not follow this naming convention (or data type).
I'm looping through $rec_items with a foreach loop. I would like to be able to dynamically cycle through key names in $rec_items, and 'do something' when a key is found that matches title*. I've tried pushing numeric numbers from a counter variable into key names to be searched for (like below):
foreach ($rec_items as $key => $value){
$c = 0;
if(!empty($key[${'title'.$c}]){
$c++;
//do something
}
I believe that I cannot pass the value ${'title'.$c} into $key[] and have tried to pass the value of ${'title'.$c} as a string with no luck.
I just share the above to try to highlight what i'm trying to achieve.
(1) dynamically loop through key names in the format 'title*'
(2) if the key name is present in the $rec_items array ... do something.
I'm not sure what your original code was trying for; you appeared to be treating the array key like an array itself? Using a variable variable? Anyway, you just need a simple string search of the key. You can use regular expressions or whatever you like for more complex matching.
<?php
$rec_items = ["foo"=>12, "bar"=>34, "title1"=>56, "title2"=>78, "baz"=>90];
foreach ($rec_items as $k=>$v) {
if (strpos($k, "title") === 0) {
echo "$k = $v\n";
}
}
Output:
title1 = 56
title2 = 78

Get value out of Array

I am trying to get a certain value out of an array.
Example of the array is:
array(2) {
["error"]=>
array(0) {
}
["result"]=>
array(1) {
["open"]=>
array(1) {
["12345-AAAAA-66AAKK"]=>
array(14) {
["inf"]=>
Usually when I want a certain value I would use:
$datawanted=$data[result][open][value];
However, in this case the first array is a variable that always changes (12345-AAAAA-66AAKK), I need to find the value of that.
I tried getting this with reset() and key[0] but this not give the wanted result.
Is there a way to get the output of the first element in the result array?
You can use array_search: http://php.net/manual/de/function.array-search.php
Example:
foreach ($array['result']['open'] as $dynamicKey => $item) {
if ($key = array_search('Value you are looking for', $item) {
$datawanted=$array['result']['open'][$dynamicKey][$key];
}
}
$data[result][open] is not a correct way to access array items.
The token result looks like a constant. PHP searches for a constant named result, cannot find one and triggers a notice. Then it thinks "I guess the programmer wanted to write 'result' (a string, not a constant). I'll convert it as string to them." and uses 'result' instead.
It works but it's a horrible practice. It dates from the prehistory of PHP, 20 years ago and it's not recommended.
After you fix your code to correctly denote the keys of an array, the next step is to pick one of the many PHP ways to access values in the array.
You can get the first value of an array without knowing its key ($data['result']['open']['12345-AAAAA-66AAKK']) by using the function reset():
$datawanted = reset($data['result']['open']);
Or you can use the function array_values() to get only the values of the array (the keys are ignored, the returned array have the values indexed from zero) then your desired data is at position 0 on this array:
$values = array_values($data['result']['open']);
$datawanted = $values[0];
Another option, if you don't need to keep $data for further processing, is to use the PHP function array_shift() to remove the first value from the array and return it. Be warned that this function modifies the array it receives as argument:
$datawanted = array_shift($data['result']['open']);
If you need to process all the values of $data['result']['open'] (and you probably do) then the best way is to use the foreach PHP statement. It allows you to access both the key and the value of each element of the array:
foreach ($data['result']['open'] as $key => $value) {
// $key is '12345-AAAAA-66AAKK'
$datawanted = $value;
}

Does array element has a key

How can I tell if array element, in foreach loop, has a key?
Some code:
function test($p_arr){
foreach ($p_arr as $key => $value){
// detect here if key 'came with the array' or not
}
}
$arr1['a'] = 10;
$arr2[] = 10;
$arr3[2] = 10;
test($arr1); // yes
test($arr2); // no
test($arr3); // yes
edit #1
I am aware that $arr2 also as an automated index-key. I need to know if it is automated or not.
edit #2
My use of it is simple.
In the function, I create a new array and use the $key as the new $key, if it was provided by the function call. or the $value as the new $key, if it was omitted in the function call.
I know that I can just force the use of key to each element, but in some parts of the code, the data structure itself is very dynamic* - and i'm trying to stay flexible as much as possible.
*code that create other code, that create ... and so on.
There is no difference between explicit keys and implicit keys generated via []. The [] doesn't mean "give this element no key", it means "use the next key for this element".
Every element has a key
$arr1['a'] = 10; // key is the string 'a'
$arr2[] = 10; // key is will be the integer zero
$arr3[2] = 10; // key is the integer 2
Edit
Perhaps it would be good to understand why you wish to know if the index is automated or not? It seems odd.
Every array created has to have a key, whether it's a integer or string as the key or index, without no index the PHP would have no way to interpret or even pull information from the array it's self.
$Var = array ("String","anotherstring","sdfhs","dlj");
the above array will automatically be generated with a numeric index starting from 0.
$Array = array();
$Array[] = "This is a string";
The above will push information into the array, as there has been no index or key specified. It will automatically be assigned with the closest numeric value to 0, which does not already exist in the array.
$Array = array();
$Array['key'] = "This is another string";
The above will push information into the array also, but as we have specified an index with a string representation rather an automatically assigned value.
So the answer to your question, if i'm reading this Correctly.
If your referring to check if the array values are specified by PHP/The Code prior to reading the array. There is no soundproof method, as everything would need to be assigned to the array before it has data. further more, if your only adding elements to the array with a string key, then yes. It is possible.
If your relying on automatically generated numeric values, or assigning your own numeric values. it's impossible to tell if PHP has assigned this automatically, or you have specified.

PHP Compare Array Values for Validation

Ok, I have a pretty customized question so bear with me.
I basically have two sets of data that I want to compare with a lot of different possibilities.
$data = array(
'object'=>'ball', // Should check VALID (Rule 2)
'color'=>'white', // VALID (Rule 2)
'heavy'=>'no', // VALID (Rule 1)
'name'=>'wilson', // VALID (Rule 5)
'funny'=>'no' // INVALID (Rule 4)
);
$data_2 = array(
'object'=>'box', // VALID (Rule 2)
'color'=> 'blue', // VALID (Rule 2)
'texture'=>'hard', // VALID (Rule 1)
'heavy'=>'yes', // INVALID (Rule 4)
'stupid'=>'no' // INVALID (Rule 4)
// Name is INVALID because it is missing (Rule 3)
);
$required = array(
'color'=>array('white','blue'),
'heavy'=> 'no',
'name'
);
$errors = array(
'color'=>array('required'=>'Color is Required','invalid'=>'Color invalid')
'object'=>array('invalid'=>'Object invalid'),
'texture'=>array('invalid'=>'Texture invalid'),
'heavy'=>array('required'=>'Heavy is Required','invalid'=>'Heavy invalid'),
'name'=>array('required'=>'Name is Required','max_char'=>'Name exceeds char limit',
'invalid'=>'Invalid item provided',
);
$blueprint = array(
'object'=>array('box','ball'),
'color'=>array('blue','white'),
'texture'=>'hard',
'heavy'=>'no',
'name'
);
What I want to do is run $data through the $blueprint and make sure of the following:
If the $data key/value pair matches a $blueprint key/value pair, $data's k/v is valid
If the $data key/value pair matches a $blueprint key and a value from the nested array, $data's k/v is valid
If the $data array omits a key/value pair which exists in $blueprint, $data's k/v may still be valid if it is not located in the $required array
If the $data array supplies a key/value pair which does not exist in $blueprint, $data's k/v is invalid
If the $data key from a key/value pair matches a $blueprint value without a defined key, $data's k/v can still be valid. However, if the $blueprint has both a key and value defined, $data's k/v must meet the requirements of rule 1 to be valid.
I'd like to impose a character limit on several of the $blueprint k/v where if a $data's k/v exceeds this character limit, $datas k/v is not valid
If a $data's k/v is invalid, I'd then like to somehow associate an error with that particular k/v describing why it is invalid (surpassed character limit, general error etc.) Perhaps the error would be defined in a third array?
I've looked into array_intersect_assoc but not sure if this is beyond the scope of that function. Also, there will be a good amount of values in the $blueprint, so I need something as versatile as possible.
I think that this is right, my brain sort of melted while I was writing this, so please don't hesitate to ask if confused. Am I better off just validating each k/v individually?
Let's see who is the brainiac out there.
I made one change to your sample code. It seems easier if you make name into a key rather than a numerically keyed value.
$required = array(
'color'=>array('white','blue'),
'heavy'=> 'no',
'name' => '', # name now a key
);
This now works for a number of your rules. Primarily checking required keys exist, and that no extra keys outside of required and blueprint exist.
# check required keys
$missing = array_diff_key($required, $data);
if($missing) {
var_dump($missing); # react to missing keys
}
# check against all possible keys
$possible = array_merge_recursive($blueprint, $required);
$extra = array_diff_key($data, $possible);
if($extra) {
var_dump($extra); # react to extra keys
}
Now for the rest I would really need to know how you respond to malformed data etc. but if your data now passes these two tests and you respond in the way you see fit, you should be clear to iterate through the array and validate using array_search(), and filter_var() to check lengths.
I feel sort of silly, but here's a brute force method. #6 you get for free because it's not 'in' the array in any sense.
foreach ($data as $k => $v) {
if (empty($blueprint[$k])) {
// (3) Data defines a key that isn't defined in blueprint.
} else {
if (is_array($blueprint[$k])) {
if (in_array($v, $blueprint[$k])) {
// (2) Data defines a valid value in a blueprint list.
} else {
// (also 4) Data defines a value not in a blueprint list.
}
} else if ($v == $blueprint[$k]) {
// (1) Data defines a value in the blueprint.
} else if (in_array($v, $blueprint)) {
// (5) Data is in the blueprint without a key.
} else {
// (4) Data is invalid.
}
}
}
EDIT: This is the loop for checking if $blueprint has a key that $data doesn't define. There should probably be a toggle to make sure this is at all necessary (in the previous block) before running it.
foreach ($blueprint as $k => $v) {
if (empty($data[$k])) {
// (6) Data doesn't have a required key from blueprint.
}
}
Truth be told, that's not that difficult per se, its just complex. You can use the array_map function to simplify the mapping; it would look like this:
function validate_data($data, $blueprint)
{
// an implementation of all that stuff you wrote using lots of
// for loops and if statements
}
array_map('validate_data', $data, $blueprint);
Check out the man page for more specifics. You can be the braniac this time :)
You want to use in_array(). It will search through the values of your array and find the different values, eg.
foreach($data as $key => $val) {
$check = in_array($val, $blueprint);
if($check === false) {
print("invalid");
die;
}
}
Yes, you probably have to code it youself, as I don't think there is any internal function that can do this. Shouldn't be too hard as you already have a good description of your requirements - just translate it into PHP.

PHP key value pairs vs. arrays

I'm trying to pass key values pairs within PHP:
// "initialize"
private $variables;
// append
$this->variables[] = array ( $key = $value)
// parse
foreach ( $variables as $key => $value ) {
//..
}
But it seems that new arrays are added instead of appending the key/value, nor does the iteration work as expect. Please let me know what the proper way is.
Solution
$this->variables[$key] = $value;
did the trick - the iteration worked as described above.
I think you may be looking for:
$this->variables[$key] = $value;
The way you have it right now you are creating an array of arrays, so you would have to do this:
foreach($this->variables as $tuple) {
list($key, $value) = $tuple;
}
Referring to Perl, but helps understand the difference between hashes and arrays:
Some people think that hashes are like arrays (the old name 'associative array' also indicates this, and in some other languages, such as PHP, there is no difference between arrays and hashes.), but there are two major differences between arrays and hashes. Arrays are ordered, and you access an element of an array using its numerical index. Hashes are un-ordered and you access a value using a key which is a string.
Source: http://perlmaven.com/perl-hashes

Categories