6

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.

Tom Auger
  • 19,421
  • 22
  • 81
  • 104
  • Well that is a bit of a catch 22 you got yourself there. Either move ahead and suppress notices (they don't stop script execution, they are like PHP's way of saying "hey now....") or initialize the array element before you use it and PHP will leave you alone. – Crackertastic Oct 23 '13 at 23:50
  • 3
    Either use `@` which is the language built-in very specifically for this (important: notices are still generated, for instance the log, just not displayed per default), or create an increment wrapper `function inc(&$var) { return ++$var; }` which implicitly creates the local var name. – mario Oct 23 '13 at 23:53

3 Answers3

5

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;
Max Zuber
  • 1,217
  • 10
  • 16
2

Suppress the error using @ for now:

@$matched_tags[$tag]++;
qaphla
  • 4,707
  • 3
  • 20
  • 31
Steve Horvath
  • 508
  • 1
  • 4
  • 10
  • Hmmm. While this will definitely do the trick, it concerns me. My understanding of @ in this usage is to suppress errors during OS functions. I'm not sure I've seen it used this way to get around a nuance of the language. – Tom Auger Oct 24 '13 at 00:54
  • @TomAuger I have done this on occasion, it's not perfect, but it works well enough - as long as you understand the implications for the rest of your own code (in your case, pretty much non-existant) – Fluffeh Oct 24 '13 at 02:21
  • yeah it's not a perfect solution by any means, but at least it's perfectly simple to suit immediate needs :) – Steve Horvath Oct 24 '13 at 02:59
1

Are ternary operators any less painful?

array_key_exists( $tag, $matched_tags ) ? $matched_tags[$tag]++ : $matched_tags[$tag] = 1;
Jason
  • 1,987
  • 1
  • 14
  • 16