I’d finally got fed up with this behavior, and just last night got a helpful hint about it in #emacs on freenode (I’ve forgotten your nick, but thank you, if you read this).
The problem is, when you end a line with a paren still open, and continue your code on the next line, most of the cc-mode indentation styles consider this an “unfinished argument list” and specify to indent the next line over to the column just to the right of that open paren. This looks fine in C and its ilk – the idea is that you’re probably doing this because you have a function with a lot of parameters, so it keeps your arguments (or parameters) all lined up together like they’re in a list. You see this sort of thing in Ada code quite a bit too, I think.
Where this really falls down though, is when you’re coding PHP. In PHP you do a lot of literal associative arrays in your code – stuff like this:
$expected = array(
'id' => 1,
'last_name' => 'Jones',
'first_name' => 'Robert',
'middle_inital' => 'F',
'ssn' => '999-99-9999',
'dob' => '1978-12-17');
In this case, the whole reason I’m continuing the contents of the array on a new line is because I don’t want the line to be super ugly long. If I’d wanted this stuff indented way over by the opening paren of “array(“, I wouldn’t have put in a new line in the first place. To make matters worse, sure you can go back over and delete that extra whitespace and indent it where you want, but once you add to or edit that line again, emacs very rudely shoves it back over where it wants it.
Without going into a whole tutorial on how emacs defines indentation rules (which I’m not at all qualified to do, but seems fascinating), you can redefine an indent rule by putting your cursor in the spot where the offending rule is taking place and hit C-c C-o to see what “context” emacs considers it. Hit return to change the setting for that context, and you’ll be asked to enter a new setting using some little syntax of symbols that emacs uses. I don’t know them all, but I have figured out that “0” means “don’t indent at all” and “+” means “indent one level” (where the amount of indentation for a level is defined by the c-basic-offset variable). + is the one I wanted.
I will note, however, that it’s sensitive to how many sets of parens you have open, so if you end a line two open-parens deep, that next line will be indented twice. For example:
array('last_name' => '')),
"Last name should be required");
But I can live with that.
Of course you don’t want to have to do this dance every time you open a PHP file, so you’ll want to put it in your .emacs or .emacs.d/init.el somewhere. In case you haven’t run across this yet, after performing most actions in emacs you can hit C-x ESC ESC to see the elisp code for what you just did in your minibuffer (where you can also edit and re-run it if you like.) In this case, the elisp code it gave me was:
(c-set-offset (quote arglist-cont-nonempty) (quote +) nil)
; alternately, using ' as shortcut for quote:
(c-set-offset 'arglist-cont-nonempty '+ nil)
If you also do a bit of C programming, you may want to only have this affect PHP files, in which case, slap it in a mode-hook.
You can also set the size of indentation, and things like whether you want tabs or spaces, and what kind of indentation/brace style you prefer (check out M-x c-set-style to experiment a bit – I’m a k&r man, myself) but you should be able to google up the same stuff I did for that.