PHP Code Compliance In Emacs

July 01, 2011 at 09:00 AM | categories: php, emacs | View Comments

My job has me working on a project in PHP right now -- it sure isn't Python, but PHP has grown up considerably since the last time I used it, which has been awhile. Consequently, I have no Emacs config for PHP setup, other than vanilla php-mode, so I went in search of one. Of course, I knew Sacha Chua would have a great one, so that's where I've started.

My code is required to conform to the PEAR coding standards which is a bit pedantic in places, but it's generally a good reference to make clean and readable code. The only real pain in conforming to a coding standard is if your editor doesn't pick up on your mistakes right away, you get no automatic feedback and you're left with the task of cleaning up your code later at an inconvenient time. In my case, a subversion pre-commit hook checks for compliance and prevents me from checking in non-conforming code just when I thought I was ready to go home!

Sacha's configuration only checks for general syntax errors, it doesn't check for code compliance. For that, I'm using PHP_CodeSniffer which performs a static analysis of a PHP file and notes any deviations for a given standard. They even support Emacs compile mode out of the box. Compile mode still doesn't give me automatic feedback though, for that I still wanted to use flymake like Sacha has.

So here's my elisp for configuring Emacs to automatically highlight both syntax errors and coding standard deviations for PHP:

(require 'php-mode)
(require 'flymake)

;; Pear coding standards :
(defun pear/php-mode-init ()
  "Set some buffer-local variables."
  (setq case-fold-search t)
  (setq indent-tabs-mode nil)
  (setq fill-column 78)
  (setq c-basic-offset 4)
  (c-set-offset 'arglist-cont 0)
  (c-set-offset 'arglist-intro '+)
  (c-set-offset 'case-label 2)
  (c-set-offset 'arglist-close 0))
(add-hook 'php-mode-hook 'pear/php-mode-init)

(defun my-php-hook-function ()
  (set (make-local-variable 'compile-command) (format "php_lint %s" (buffer-file-name))))
(add-hook 'php-mode-hook 'my-php-hook-function)

(defun flymake-php-init ()
  "Use php and phpcs to check the syntax and code compliance of the current file."
  (let* ((temp (flymake-init-create-temp-buffer-copy 'flymake-create-temp-inplace))
     (local (file-relative-name temp (file-name-directory buffer-file-name))))
    (list "php_lint" (list local))))

;;This is the error format for : php -f somefile.php -l 
(add-to-list 'flymake-err-line-patterns
  '("\\(Parse\\|Fatal\\) error: +\\(.*?\\) in \\(.*?\\) on line \\([0-9]+\\)$" 3 4 nil 2))

(add-to-list 'flymake-allowed-file-name-masks '("\\.php$" flymake-php-init))
(add-hook 'php-mode-hook (lambda () (flymake-mode 1)))

This depends on a small BASH helper script which I have stored in my $HOME/bin directory (which is on my PATH by default):

#This does standard PHP syntax checking
php -f $1 -l
#This does coding standard checking
phpcs --standard=PEAR --report=emacs $1
#Always exit with status code 0 otherwise flymake complains
exit 0

Now I get nice red highlighting for when I forget a doc tag or to put a space between parens and brackets. Isn't pedantry great? :/

blog comments powered by Disqus