Drupal - Why is it sometimes $node->field_name[0], and sometimes $node->field_name['und'][0]?

The lack of the 'und', or LANGUAGE_NONE level data seems to indicate that the field has lost the ability to be translated. I've never encountered such a field.

field_get_items() as already pointed out is the canonical way to safely retrieve field data. Any fields that don't work with field_get_items should be considered broken.

I would hazard a guess that you either

  1. Have a broken contrib module that re-arranges field data and doesn't know better than to sometimes remove the language level.
  2. Your field settings have just broken somewhere along the way. Potentially because of a reason similar to above.

Does the problem keep happening on newly created fields?

Can you reproduce on a clean install?

I believe you need a combination of field_get_items() and field_view_value().

In your case (I can't test this):

$item = field_get_items('node', $node, 'field_phone'); // unsafe to print
$output = field_view_value('node', $node, 'field_phone', $item[0]);
print $output;

EDIT: In the above code, line 2 ($output = ...), I added in $item[0] because I failed to see that $item requires a delta. This allows for fields which have multiple values to be iterated over and passed through field_view_value(). I believe you are skipping the important step of using field_view_value().

If using the above code (including field_view_value()) doesn't solve this, I would need more information; e.g. seeing your node.tpl.php and possibly a content type export.