4

I'm using the PHP shorthand addition operator to tally the number of times a specific id occurs within a multidimensional array:

$source['tally'] = array();

foreach ($items as $item) {
    $source['tally'][$item->getId()] += 1;
}

The first time it hits a new id, it sets its 'tally' value to 1 and then increments it each time it's found thereafter.

The code works perfectly (I get the correct totals), but PHP gives me an "Undefined Offset" notice each time it finds a new id.

I know I can just turn off notices in php.ini, but figured there must be a reason why PHP doesn't approve of my technique.

Is it considered bad practice to create a new key/offset dynamically like this, and is there a better approach I should take instead?

Please Note: To help clarify following initial feedback, I do understand why the notice is being given. My question is whether I should do anything about it or just live with the notice. Apologies if my question didn't make that clear enough.

4
  • 1
    $source['tally'] = array(); is a raw array. There is no initialization. that might be the reason. Guess so Commented Nov 15, 2011 at 6:40
  • Thanks - the notice is given with or without the initialization code. Leaving off that line just adds an "undefined index" notice in addition to the "undefined offset" notice already mentioned. Commented Nov 15, 2011 at 6:50
  • offset is also, similar, since it contains no value, as ur offset is not yet defined, '+=' tries to add to a pre-exisitng value; So it assigns a warning first time. Commented Nov 15, 2011 at 6:52
  • Does anyone know how to use this shorthand operator += within the PHP 8 limitations of warnings being given when trying to add to an unset value. This causes code bloat esp. for dynamically generated values. Are there any workarounds? Commented Mar 30, 2022 at 11:43

4 Answers 4

5

You have to understand that PHP notices are a tool. They exist so you have additional help when writing code and you are able to detect potential bugs easily. Uninitialized variables are the typical example. Many developers ask: if it's not mandatory to initialize variables, why is PHP complaining? Because it's trying to help:

$item_count = 0;
while( do_some_stuff() ){
     $iten_count++; // Notice: Undefined variable: iten_count
}
echo $item_count . ' items found';

Oops, I mistyped the variable name.

$res = mysql_query('SELECT * FROM foo WHERE foo_id=' . (int)$_GET['foo_id']);
// Notice: Undefined index: foo_id

Oops, I haven't provided a default value.

Yours is just another example of the same situation. If you're incrementing the wrong array element, you'd like to know.

Sign up to request clarification or add additional context in comments.

1 Comment

The concept of forcing a code block to define a default value when the code variables (such as array contents) can be completely dynamically generated is not bad per-say but it's bad that it's marked in PHP 8+ as a warning level error
4

Using += (or any of the other augmented assignment operators) assumes that a value already exists for that key. Since this is not the case the first time the ID is encountered, a notice is emitted and 0 is assumed.

4 Comments

Thanks for the response. I understand why the notice is emitted, but why does PHP care whether a value already exists for the key -- since it's just going to follow my directions and set the value to 1 anyway? Is there a reason it's not considered good practice to do it this way, even though it works?
It's not going to set it until it has retrieved the value that already exists with that key. But there is no element with that key in the first place.
Because it's likely to be an error if you try to read a value that doesn't exist.
PHP allows this behavior, it doesn't give you an error, it just gives you a notice, because although your script still works it is bad programming practice, and will not work if you do this in other languages.
3

It's caused because you don't initialize your array to contain the initial value of 0. Note that the code would probably work, however it is considered good practice to initialize all the variable you are about to preform actions upon. So the following code is an example of what you should probably have:

<?php
    $source['tally'] = array();

    foreach ($items as $item) {
        //For each $item in $items,
        //check if that item doesn't exist and create it (0 times).
        //Then, regardless of the previous statement, increase it by one.
        if (!isset($source['tally'][$item->getID()]) $source['tally'][$item->getID()] = 0;
        $source['tally'][$item->getId()] += 1;
    }
?>

The actual reason why PHP cares about it, is mainly to warn you about that empty value (much like it would if you try to read it). It is a kind of an error, not a fatal, script-killing one, but a more subtle quiet one. You should still fix it though.

Comments

0

If you simply want to hide the notice, you can use the error control operator:

$source['tally'] = array();

foreach ($items as $item) {
    @$source['tally'][$item->getId()]++;
}

However, you should generally initialize your variables, in this case by adding the following code inside the loop:

if (!isset( $source['tally'][$item->getId()] ))
{
   $source['tally'][$item->getId()] = 0;
}

5 Comments

It's not that his code isn't wrong, and it's not about getting rid of the notice. Initializing values is considered good practice. If he had attempted this not in PHP but in C++, the code would go crazy.
At least the OP has notices switched on, and is actually paying attention to them.
On PHP 8 this becomes a warning and forces out a large amount of code bloat :-(
@hakre You're welcome to add your own answer, rather than change an existing answer completely.
That "error control operator" would suppress all possible errors in getId() method as well, possibly leading to debugging problems. I wish this answer never existed. Such answers are the reason why PHP is so much hated. People get an impression that such code is a norm.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.