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.
Related
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 ?
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.
Every time I try to run my code I am getting a 'Notice: Undefined offset: 1 Error
specifically coming from this line:
$acmark= $summary[1][1] += $student[$row][2] / 25;
I am new to PHP and would like to get this working with the least amount of changes possible. I have uploaded the full source code to Pastebin to make for easier viewing.
http://pastebin.com/Ur8u673V
Thanks in advance guys, Luke.
Looking at the code in your paste, you're initialising $summary to an empty array, and never actually adding anything to it before attempting to read the data. It's equivalent to:
$summary = array();
// ...
$acmark = $summary[1][1] += $student[$row][2] / 25; // $summary[1] isn't defined
Agree with George - you're initializing $summary as an array, but the offset starts at 0. Since you're incrementing in a loop, change line 140 to:
$acmark = $summary[][] += $student[$row][2] / 25;
That will eliminate the notice. You can apply the same solution to the other lines with undefined offsets as well to resolve the other notices.
Consider using an associative array(s) with foreach loops so the array keys are more meaningful. Associative arrays are easier to use and support the idea of using self-documenting code
i think u should set value of array first (maybe with 0), because if undefines is meaning that array is null value (null is different with 0)
add this code after $summary = array(); like below
$summary=array();
//additional code
for($sum=0; $sum<6; $sum++)
$summary[$sum][1]=0;
for($row=0; $row<25; $row++){
.
.
.
I'd like to do this:
$matched_tags[$tag]++
As a simple way of keeping track of how many times a given $tag is found during a loop.
This appears to be throwing a NOTICE the first time any new $tag is encountered, because the index is undefined. PHP kindly autovivifies it, sets it to 0 and post-increments it, but throws the NOTICE anyway.
Now I like to develop with Notices on as a best practice, so I don't want to suppress them. But to me what I'm doing isn't notice-worthy.
Do I really have to:
if ( ! isset ( $matched_tags[$tag] ) ) $matched_tags[$tag] = 0;
$matched_tags[$tag]++;
Oh that is so painful. Please tell me there's a more elegant way, or I swear I'll switch to Perl so help me.
I found another way to increment undefined array items. It looks like a kind of a hack, but it's obvious and still short.
Suppose you need to increment a leaf value of the few nested arrays. Using isset() it may be too annoying:
<?php
error_reporting(E_ALL);
$array['root']['node'][10]['node'][20]['leaf'][30]['totalCount'] =
isset($array['root']['node'][10]['node'][20]['leaf'][30]['totalCount'])
? ($array['root']['node'][10]['node'][20]['leaf'][30]['totalCount'] + 1)
: 1;
Name of an array item repeated there three times, rippling in your eyes.
Try to use & operator to get an array item reference. Acting with a reference not causing any notices or errors:
<?php
error_reporting(E_ALL);
$item = &$array['root']['node'][10]['node'][20]['leaf'][30]['totalCount'];
// $item is null here
$item++;
unset($item);
echo $array['root']['node'][10]['node'][20]['leaf'][30]['totalCount']; // 1
It works just fine, but you can also avoid null to 0 casting:
<?php
error_reporting(E_ALL);
$item = &$array['root']['node'][10]['node'][20]['leaf'][30]['totalCount'];
// $item is null here
$item = isset($item) ? ($item + 1) : 1;
unset($item);
echo $array['root']['node'][10]['node'][20]['leaf'][30]['totalCount']; // 1
If you're already on PHP7, use coalesce operator instead of isset():
$item = ($item ?? 0) + 1;
Suppress the error using # for now:
#$matched_tags[$tag]++;
Are ternary operators any less painful?
array_key_exists( $tag, $matched_tags ) ? $matched_tags[$tag]++ : $matched_tags[$tag] = 1;
If accessing an undefined index of a null reference, PHP does not throw any errors.
<?php
$array = &$foo['bar'];
if ($array['stuff']) echo 'Cool'; // No PHP notice
$array['thing'] = 1; // Array created; $foo['bar']['thing'] == 1
$array['stuff']; // PHP notice
If $array wasn't a reference PHP would have complained on the first line.
Why doesn't it for references? Do I need bother with isset for null references, or is PHP complaining internally and not letting me know?
In your code $array is null. The following code will not give you a notice either:
$b = null;
if ($b['stuff']) echo 'cool';
This is strange, this comment in the documentation points to that fact.
You must raise your error reporting level. Your example $array['stuff'] will throw warnings about index not found. I often combine a test for key in with the evaluation so as to prevent those warnings:
if( array_key_exists("blah",$arr) && strlen($arr['blah']) > 0 ) {
; // do stuff here
}
I often combine variables in with array names because anytime I have to cut-n-paste copy code to the next section to do the same-ish thing, I'd rather make an array of variable names and then iterate through the variable names. The most absurd condition is when I have billing and shipping data to manipulate, where I'll have an array variable name $BorS or just $BS and then at the top, set $BorS="shipping"; and end up with really interesting statements like:
${$BorS."data"}[${$BorS."_addr1"}]=$input_array[$BorS."_address_line_1"];
Why not just do:
$array = array();