I have this case to assign values to associative arrays.
for($i=0;$i<$dynamicNumber;$i++){
for($j=0;$j<$dynamicNumber2;$j++){
$array[$i][$j]['key'] += $value;
}
}
Because is an addition operator it will first look for the array key value and add with the $value.
Since the key is not defined previously it will throw and "undefined index" error in the first loop.
I am in a process of converting and old php project and this case is like thousand times.
My shortest way is doing it like:
for($j=0;$j<$dynamicNumber2;$j++){
$array[$i][$j]['key'] = ($array[$i][$j]['key'] ?? 0) + $value;
}
Can this be improved ?
Related
This question already has answers here:
Notice: Undefined index when trying to increment an associative array in PHP
(6 answers)
Closed 4 months ago.
I want to increment a value of an array, which is potentially not existing yet.
$array = [];
$array['nonExistentYet']++; // Notice
Problem
This leads to a NOTICE.
Attempt
I found a way to do this, but its kinda clunky:
$array = [];
$array['nonExistentYet'] = ($array['nonExistentYet'] ?? 0) + 1;
Question
Is there a more human readable/elegant way to do this?
well i guess a more readable way would be to use if..else as,
$arr = [];
if(array_key_exists('nonExistentYet', $arr)) {
$arr['nonExistentYet'] += 1;
}
else {
$arr['nonExistentYet'] = 1;
}
If this is used often, you can define a little helper method, which also uses an interesting side effect...
function inc(&$element) {
$element++;
}
$array = [];
inc($array['nonExistentYet']);
print_r($array);
gives...
Array
(
[nonExistentYet] => 1
)
with no warning.
As you can see the function defines the parameter as &$element, if this value doesn't exist, then it will be created, so the function call itself will create the element and then it will just increment it.
My standard implementation for this is:
if (isset($array['nonExistentYet']))
$array['nonExistentYet']++;
else
$array['nonExistentYet'] = 1;
But this is one of the rarely scenarios where I use the # operator to suppress warnings, but only if I have full control over the array:
#$array['nonExistentYet']++;
Generally, it is not good to suppress warnings or error messages!
What you ask is a little vague,
Either the variable exists and you increment it, or it does not exist in this case you create it.
In another case suppose that you want to do it in a for loop, in this case you do not have to worry about the existence of the variable.
One way is ternary operator, which checks if array value exists:
$array['iDoNotExistYet'] = empty($array['iDoNotExistYet']) ? 1 : ++$array['iDoNotExistYet'];
Other one would be just rewriting it to if and else condition.
This question already has answers here:
Notice: Undefined index when trying to increment an associative array in PHP
(6 answers)
Closed 4 months ago.
I have a foreach loop, inside of which I am building a big multi-dimensional array and doing lots of incriminating, like this:
$totalCosts['sawn']['materials'] += $sawnMaterialsCost;
On the first iteration of the loop, the key 'materials' is not set, so it throws an undefined index notice (not terrible, but annoying).
I can fix that by defining it before the loop like this:
$totalCosts['sawn']['materials'] = '0.00';
BUT, I have many keys I am filling by incrementing, and I don't like having to set each variable/key to '0' for every one before looping. Is there a better way to do this so the first iteration of the loop checks for a value and sets it to 1 if not found?
$totalCosts['sawn']['materials'] = ($totalCosts['sawn']['materials'] ?? 0) + $sawnMaterialsCost;
??, an operator introduced in PHP 7, uses the left-hand operand if defined and not null, otherwise the right-hand operand.
The performance cost of ?? is negligible, unless you are doing millions of comparisons. On an Amazon c3.medium, I measured each at ~250ns more than a static assignment. On a loop of 10,000,000 that's a half-second penalty.
perf.code.
Yes - first check if it exists, and if not, create it.
foreach($something as $key) { //e.g. $key = 'materials'
if (!isset($totalCosts['sawn'][$key])) $totalCosts['sawn'][$key] = 0;
$totalCosts['sawn'][$key] += $sawnMaterialsCost;
}
Well, I don't think there is a solution way more compact than this:
foreach(...) {
if(!isset($totalCosts['sawn'][$yourkey]))
$totalCosts['sawn'][$yourkey] = 0.00;
$totalCosts['sawn'][$yourkey]+=$sawnMaterialsCost;
}
Using the ternary operator is one way you can accomplish this.
$totalCosts['sawn']['materials'] = !empty($totalCosts['sawn']['materials']) ? $totalCosts['sawn']['materials'] + $sawnMaterialsCost : $sawnMaterialsCost;
This way you won't try adding to a non-existent value.
Are arrays passed by reference or value in PHP?
For example, let's see this code.
function addWeight($arout, $lineCountry, $lineDomain, $target, $weight)
{
$currentDomain=getDomain();
$currentCountry=getCountry();
if ($currentCountry==$lineCountry && ($currentDomain == $lineDomain || $lineDomain==""))
{
$tarobreakpoint=0;
$arout [$target] = intval($weight);
}
return $arout;
}
Basically it took an array as a parameter. Depending on some circumstances it adds elements to the array. I wonder if this is efficient? If $arout is passed by reference like all arrays should then I think it's efficient. But if it's just copied and passed by value then well it's not.
So what's the verdict?
According to the manual, PHP arrays are passed by value:
Array assignment always involves value copying. Use the reference operator to copy an array by reference.
If you'd like to pass an array's reference, use the corresponding operator (&) as mentioned above, and remove the return $arout; line in the addWeight() function:
<?php
// pass $array by reference using & operator
addWeight(&$array, $lineCountry, $lineDomain, $target, $weight);
The empty() function in php 5.3 does not work well for associative arrays. I have an associative array that could have some 30+ elements.
$arr = array(
'one'=>kwara,
'two'=>osun,
...
'thirty'=>lagos
)
If the associative array is empty like so:
$arr = array(
'one'=>'',
'two'=>'',
...
'thirty'=>''
)
and I need to check if the array is empty, the following will not work in php 5.3.
if(empty($arr))
{
echo "array is empty<br />>";
}
else
{
echo "array is NOT empty<br />";
}
and will return 'array is NOT empty'. I am aware that the behaviour is different in php 5.4 but my current platform is php 5.3.
To overcome this problem, I have used the following:
if(strlen(implode('',array_values($arr))) > 0)
{
echo "array is NOT empty<br />>";
}
else
{
echo "array is empty<br />";
}
The question is: is there a better of achieving this in php 5.3?
Short answer: No
Longer answer: The array you are looking at is not empty at all, it contains a bunch of keys with zero length strings. Your solution is probably one of the shortest possible and readable. You may want to wrap it in a function of your own though.
Have you tried:
if (sizeof(array_filter($array)) === 0) // do your stuff
Also you original could be improved like:
if (implode($array) !== '') // do your stuff
Empty will work only with really empty values, your array has keys assigned so its not empty. Your solution is probably best way to do what you want - its hard to say, you would need to make some benchmarks, it can be done in many other ways:
if (array_filter($arr) === array()) {}
// or
if (!implode('', $arr)) {}
We gave a given array which can be in 4 states.
array has values that are:
only arrays
only non-arrays
both array and non array
array has no values
Considering than an array-key can only be a numerical or string value (and not an array), I suppose you want to know about array-values ?
If so, you'll have to loop over your array, testing, for each element, if it's an array or not, keeping track of what's been found -- see the is_array function, about that.
Then, when you've tested all elements, you'll have to test if you found arrays, and/or non-array.
Something like this, I suppose, might do the trick :
$has_array = false;
$has_non_array = false;
foreach ($your_array as $element) {
if (is_array($element)) {
$has_array = true;
} else {
$has_non_array = true;
}
}
if ($has_array && $has_non_array) {
// both
} else {
if ($has_array) {
// only arrays
} else {
// only non-array
}
}
(Not tested, but the idea should be there)
This portion of code should work for the three first points you asked for.
To test for "array has no value", The fastest way is to use the empty() language construct before the loop -- and only do the loop if the array is not empty, to avoid any error.
You could also count the number of elements in the array, using the count() function, and test if it's equal to 0, BTW.
Some precalculation:
function isArray($reducedValue, $currentValue) {
// boolean value is converted to 0 or 1
return $reducedValue + is_array($currentValue);
}
$number_of_arrays = array_reduce($array, 'isArray', 0);
Then the different states can be evaluated as follows:
only arrays
count($array) == $number_of_arrays
only non-arrays
$number_of_arrays == 0
both array and non array keys
count($array) != $number_of_arrays
array has no keys
empty($array);
So you just need to write a function that returns the appropriate state.
Reference: in_array, array_reduce, empty