-
-
-
-
-
+;;; php-mode.el --- major mode for editing PHP code
+
+;; Copyright (C) 1999, 2000, 2001, 2003, 2004 Turadg Aleahmad
+;; 2008 Aaron S. Hawley
+
+;; Maintainer: Aaron S. Hawley
+;; Author: Turadg Aleahmad, 1999-2004
+;; Keywords: php languages oop
+;; Created: 1999-05-17
+;; Modified: 2008-11-04
+;; X-URL: http://php-mode.sourceforge.net/
+
+(defconst php-mode-version-number "1.5.0"
+ "PHP Mode version number.")
+
+;;; License
+
+;; This file is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 3
+;; of the License, or (at your option) any later version.
+
+;; This file is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this file; if not, write to the Free Software
+;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+;; 02110-1301, USA.
+
+;;; Usage
+
+;; Put this file in your Emacs lisp path (eg. site-lisp) and add to
+;; your .emacs file:
+;;
+;; (require 'php-mode)
+
+;; To use abbrev-mode, add lines like this:
+;; (add-hook 'php-mode-hook
+;; '(lambda () (define-abbrev php-mode-abbrev-table "ex" "extends")))
+
+;; To make php-mode compatible with html-mode, see http://php-mode.sf.net
+
+;; Many options available under Help:Customize
+;; Options specific to php-mode are in
+;; Programming/Languages/Php
+;; Since it inherits much functionality from c-mode, look there too
+;; Programming/Languages/C
+
+;;; Commentary:
+
+;; PHP mode is a major mode for editing PHP 3 and 4 source code. It's
+;; an extension of C mode; thus it inherits all C mode's navigation
+;; functionality. But it colors according to the PHP grammar and indents
+;; according to the PEAR coding guidelines. It also includes a couple
+;; handy IDE-type features such as documentation search and a source
+;; and class browser.
+
+;;; Contributors: (in chronological order)
+
+;; Juanjo, Torsten Martinsen, Vinai Kopp, Sean Champ, Doug Marcey,
+;; Kevin Blake, Rex McMaster, Mathias Meyer, Boris Folgmann, Roland
+;; Rosenfeld, Fred Yankowski, Craig Andrews, John Keller, Ryan
+;; Sammartino, ppercot, Valentin Funk, Stig Bakken, Gregory Stark,
+;; Chris Morris, Nils Rennebarth, Gerrit Riessen, Eric Mc Sween,
+;; Ville Skytta, Giacomo Tesio, Lennart Borgman, Stefan Monnier,
+;; Aaron S. Hawley, Ian Eure, Bill Lovett, Dias Badekas, David House
+
+;;; Changelog:
+
+;; 1.5
+;; Support function keywords like public, private and the ampersand
+;; character for function-based commands. Support abstract, final,
+;; static, public, private and protected keywords in Imenu. Fix
+;; reversed order of Imenu entries. Use font-lock-preprocessor-face
+;; for PHP and ASP tags. Make php-mode-modified a literal value
+;; rather than a computed string. Add date and time constants of
+;; PHP. (Dias Badekas) Fix false syntax highlighting of keywords
+;; because of underscore character. Change HTML indentation warning
+;; to match only HTML at the beginning of the line. Fix
+;; byte-compiler warnings. Clean-up whitespace and audited style
+;; consistency of code. Remove conditional bindings and XEmacs code
+;; that likely does nothing.
+;;
+;; 1.4
+;; Updated GNU GPL to version 3. Ported to Emacs 22 (CC mode
+;; 5.31). M-x php-mode-version shows version. Provide end-of-defun
+;; beginning-of-defun functionality. Support add-log library.
+;; Fix __CLASS__ constant (Ian Eure). Allow imenu to see visibility
+;; declarations -- "private", "public", "protected". (Bill Lovett)
+;;
+;; 1.3
+;; Changed the definition of # using a tip from Stefan
+;; Monnier to correct highlighting and indentation. (Lennart Borgman)
+;; Changed the highlighting of the HTML part. (Lennart Borgman)
+;;
+;; See the ChangeLog file included with the source package.
+
+
+;;; Code:
+
+(require 'speedbar)
+(require 'font-lock)
+(require 'cc-mode)
+(require 'cc-langs)
+(require 'custom)
+(require 'etags)
+(eval-when-compile
+ (require 'regexp-opt))
+
+;; Local variables
+(defgroup php nil
+ "Major mode `php-mode' for editing PHP code."
+ :prefix "php-"
+ :group 'languages)
+
+(defcustom php-default-face 'default
+ "Default face in `php-mode' buffers."
+ :type 'face
+ :group 'php)
+
+(defcustom php-speedbar-config t
+ "When set to true automatically configures Speedbar to observe PHP files.
+Ignores php-file patterns option; fixed to expression \"\\.\\(inc\\|php[s34]?\\)\""
+ :type 'boolean
+ :set (lambda (sym val)
+ (set-default sym val)
+ (if (and val (boundp 'speedbar))
+ (speedbar-add-supported-extension
+ "\\.\\(inc\\|php[s34]?\\|phtml\\)")))
+ :group 'php)
+
+(defcustom php-mode-speedbar-open nil
+ "Normally `php-mode' starts with the speedbar closed.
+Turning this on will open it whenever `php-mode' is loaded."
+ :type 'boolean
+ :set (lambda (sym val)
+ (set-default sym val)
+ (when val
+ (speedbar 1)))
+ :group 'php)
+
+(defvar php-imenu-generic-expression
+ '(
+ ("Private Methods"
+ "^\\s-*\\(?:\\(?:abstract\\|final\\)\\s-+\\)?private\\s-+\\(?:static\\s-+\\)?function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1)
+ ("Protected Methods"
+ "^\\s-*\\(?:\\(?:abstract\\|final\\)\\s-+\\)?protected\\s-+\\(?:static\\s-+\\)?function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1)
+ ("Public Methods"
+ "^\\s-*\\(?:\\(?:abstract\\|final\\)\\s-+\\)?public\\s-+\\(?:static\\s-+\\)?function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1)
+ ("Classes"
+ "^\\s-*class\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*" 1)
+ ("All Functions"
+ "^\\s-*\\(?:\\(?:abstract\\|final\\|private\\|protected\\|public\\|static\\)\\s-+\\)*function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1)
+ )
+ "Imenu generic expression for PHP Mode. See `imenu-generic-expression'."
+ )
+
+(defcustom php-manual-url "http://www.php.net/manual/en/"
+ "URL at which to find PHP manual.
+You can replace \"en\" with your ISO language code."
+ :type 'string
+ :group 'php)
+
+(defcustom php-search-url "http://www.php.net/"
+ "URL at which to search for documentation on a word."
+ :type 'string
+ :group 'php)
+
+(defcustom php-completion-file ""
+ "Path to the file which contains the function names known to PHP."
+ :type 'string
+ :group 'php)
+
+(defcustom php-manual-path ""
+ "Path to the directory which contains the PHP manual."
+ :type 'string
+ :group 'php)
+
+;;;###autoload
+(defcustom php-file-patterns '("\\.php[s34]?\\'" "\\.phtml\\'" "\\.inc\\'")
+ "List of file patterns for which to automatically invoke `php-mode'."
+ :type '(repeat (regexp :tag "Pattern"))
+ :set (lambda (sym val)
+ (set-default sym val)
+ (let ((php-file-patterns-temp val))
+ (while php-file-patterns-temp
+ (add-to-list 'auto-mode-alist
+ (cons (car php-file-patterns-temp) 'php-mode))
+ (setq php-file-patterns-temp (cdr php-file-patterns-temp)))))
+ :group 'php)
+
+(defcustom php-mode-hook nil
+ "List of functions to be executed on entry to `php-mode'."
+ :type 'hook
+ :group 'php)
+
+(defcustom php-mode-pear-hook nil
+ "Hook called when a PHP PEAR file is opened with `php-mode'."
+ :type 'hook
+ :group 'php)
+
+(defcustom php-mode-force-pear nil
+ "Normally PEAR coding rules are enforced only when the filename contains \"PEAR.\"
+Turning this on will force PEAR rules on all PHP files."
+ :type 'boolean
+ :group 'php)
+
+(defconst php-mode-modified "2008-11-04"
+ "PHP Mode build date.")
+
+(defun php-mode-version ()
+ "Display string describing the version of PHP mode."
+ (interactive)
+ (message "PHP mode %s of %s"
+ php-mode-version-number php-mode-modified))
+
+(defconst php-beginning-of-defun-regexp
+ "^\\s-*\\(?:\\(?:abstract\\|final\\|private\\|protected\\|public\\|static\\)\\s-+\\)*function\\s-+&?\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*("
+ "Regular expression for a PHP function.")
+
+(defun php-beginning-of-defun (&optional arg)
+ "Move to the beginning of the ARGth PHP function from point.
+Implements PHP version of `beginning-of-defun-function'."
+ (interactive "p")
+ (let ((arg (or arg 1)))
+ (while (> arg 0)
+ (re-search-backward php-beginning-of-defun-regexp
+ nil 'noerror)
+ (setq arg (1- arg)))
+ (while (< arg 0)
+ (end-of-line 1)
+ (let ((opoint (point)))
+ (beginning-of-defun 1)
+ (forward-list 2)
+ (forward-line 1)
+ (if (eq opoint (point))
+ (re-search-forward php-beginning-of-defun-regexp
+ nil 'noerror))
+ (setq arg (1+ arg))))))
+
+(defun php-end-of-defun (&optional arg)
+ "Move the end of the ARGth PHP function from point.
+Implements PHP befsion of `end-of-defun-function'
+
+See `php-beginning-of-defun'."
+ (interactive "p")
+ (php-beginning-of-defun (- (or arg 1))))
+
+
+(defvar php-warned-bad-indent nil)
+(make-variable-buffer-local 'php-warned-bad-indent)
+
+;; Do it but tell it is not good if html tags in buffer.
+(defun php-check-html-for-indentation ()
+ (let ((html-tag-re "^\\s-*?\\sw+.*?>")
+ (here (point)))
+ (if (not (or (re-search-forward html-tag-re (line-end-position) t)
+ (re-search-backward html-tag-re (line-beginning-position) t)))
+ t
+ (goto-char here)
+ (setq php-warned-bad-indent t)
+ (lwarn 'php-indent :warning
+ "\n\t%s\n\t%s\n\t%s\n"
+ "Indentation fails badly with mixed HTML and PHP."
+ "Look for an Emacs Lisp library that supports \"multiple"
+ "major modes\" like mumamo, mmm-mode or multi-mode.")
+ nil)))
+
+(defun php-cautious-indent-region (start end &optional quiet)
+ (if (or php-warned-bad-indent
+ (php-check-html-for-indentation))
+ (funcall 'c-indent-region start end quiet)))
+
+(defun php-cautious-indent-line ()
+ (if (or php-warned-bad-indent
+ (php-check-html-for-indentation))
+ (funcall 'c-indent-line)))
+
+(defconst php-tags '("" "" "="))
+(defconst php-tags-key (regexp-opt php-tags))
+
+(defconst php-block-stmt-1-kwds '("do" "else" "finally" "try"))
+(defconst php-block-stmt-2-kwds
+ '("for" "if" "while" "switch" "foreach" "elseif" "catch all"))
+
+(defconst php-block-stmt-1-key
+ (regexp-opt php-block-stmt-1-kwds))
+(defconst php-block-stmt-2-key
+ (regexp-opt php-block-stmt-2-kwds))
+
+(defconst php-class-decl-kwds '("class" "interface"))
+
+(defconst php-class-key
+ (concat
+ "\\(" (regexp-opt php-class-decl-kwds) "\\)\\s-+"
+ (c-lang-const c-symbol-key c) ;; Class name.
+ "\\(\\s-+extends\\s-+" (c-lang-const c-symbol-key c) "\\)?" ;; Name of superclass.
+ "\\(\\s-+implements\\s-+[^{]+{\\)?")) ;; List of any adopted protocols.
+
+;;;###autoload
+(define-derived-mode php-mode c-mode "PHP"
+ "Major mode for editing PHP code.\n\n\\{php-mode-map}"
+ (c-add-language 'php-mode 'c-mode)
+
+;; PHP doesn't have C-style macros.
+;; HACK: Overwrite this syntax with rules to match [^_]?")
+ '(1 font-lock-constant-face))
+
+ ;; Fontify keywords
+ (cons
+ (concat "[^_$]?\\<\\(" php-keywords "\\)\\>[^_]?")
+ '(1 font-lock-keyword-face))
+
+ ;; Fontify keywords and targets, and case default tags.
+ (list "\\<\\(break\\|case\\|continue\\)\\>\\s-+\\(-?\\sw+\\)?"
+ '(1 font-lock-keyword-face) '(2 font-lock-constant-face t t))
+ ;; This must come after the one for keywords and targets.
+ '(":" ("^\\s-+\\(\\sw+\\)\\s-+\\s-+$"
+ (beginning-of-line) (end-of-line)
+ (1 font-lock-constant-face)))
+
+ ;; treat 'print' as keyword only when not used like a function name
+ '("\\" . font-lock-keyword-face)
+
+ ;; Fontify PHP tag
+ (cons php-tags-key font-lock-preprocessor-face)
+
+ ;; Fontify ASP-style tag
+ '("<\\%\\(=\\)?" . font-lock-preprocessor-face)
+ '("\\%>" . font-lock-preprocessor-face)
+
+ )
+ "Subdued level highlighting for PHP mode.")
+
+(defconst php-font-lock-keywords-2
+ (append
+ php-font-lock-keywords-1
+ (list
+
+ ;; class declaration
+ '("\\<\\(class\\|interface\\)\\s-+\\(\\sw+\\)?"
+ (1 font-lock-keyword-face) (2 font-lock-type-face nil t))
+ ;; handle several words specially, to include following word,
+ ;; thereby excluding it from unknown-symbol checks later
+ ;; FIX to handle implementing multiple
+ ;; currently breaks on "class Foo implements Bar, Baz"
+ '("\\<\\(new\\|extends\\|implements\\)\\s-+\\$?\\(\\sw+\\)"
+ (1 font-lock-keyword-face) (2 font-lock-type-face))
+
+ ;; function declaration
+ '("\\<\\(function\\)\\s-+&?\\(\\sw+\\)\\s-*("
+ (1 font-lock-keyword-face)
+ (2 font-lock-function-name-face nil t))
+
+ ;; class hierarchy
+ '("\\<\\(self\\|parent\\)\\>" (1 font-lock-constant-face nil nil))
+
+ ;; method and variable features
+ '("\\<\\(private\\|protected\\|public\\)\\s-+\\$?\\sw+"
+ (1 font-lock-keyword-face))
+
+ ;; method features
+ '("^\\s-*\\(abstract\\|static\\|final\\)\\s-+\\$?\\sw+"
+ (1 font-lock-keyword-face))
+
+ ;; variable features
+ '("^\\s-*\\(static\\|const\\)\\s-+\\$?\\sw+"
+ (1 font-lock-keyword-face))
+ ))
+ "Medium level highlighting for PHP mode.")
+
+(defconst php-font-lock-keywords-3
+ (append
+ php-font-lock-keywords-2
+ (list
+
+ ;; or for HTML
+ ;;'("?\\sw+[^> ]*>" . font-lock-constant-face)
+ ;;'("?\\sw+[^>]*" . font-lock-constant-face)
+ ;;'("
+ '("<[^>]*\\(>\\)" (1 font-lock-constant-face))
+
+ ;; HTML tags
+ '("\\(<[a-z]+\\)[[:space:]]+\\([a-z:]+=\\)[^>]*?" (1 font-lock-constant-face) (2 font-lock-constant-face) )
+ '("\"[[:space:]]+\\([a-z:]+=\\)" (1 font-lock-constant-face))
+
+ ;; HTML entities
+ ;;'("&\\w+;" . font-lock-variable-name-face)
+
+ ;; warn about '$' immediately after ->
+ '("\\$\\sw+->\\s-*\\(\\$\\)\\(\\sw+\\)"
+ (1 font-lock-warning-face) (2 php-default-face))
+
+ ;; warn about $word.word -- it could be a valid concatenation,
+ ;; but without any spaces we'll assume $word->word was meant.
+ '("\\$\\sw+\\(\\.\\)\\sw"
+ 1 font-lock-warning-face)
+
+ ;; Warn about ==> instead of =>
+ '("==+>" . font-lock-warning-face)
+
+ ;; exclude casts from bare-word treatment (may contain spaces)
+ `(,(concat "(\\s-*\\(" php-types "\\)\\s-*)")
+ 1 font-lock-type-face)
+
+ ;; PHP5: function declarations may contain classes as parameters type
+ `(,(concat "[(,]\\s-*\\(\\sw+\\)\\s-+&?\\$\\sw+\\>")
+ 1 font-lock-type-face)
+
+ ;; Fontify variables and function calls
+ '("\\$\\(this\\|that\\)\\W" (1 font-lock-constant-face nil nil))
+ `(,(concat "\\$\\(" php-superglobals "\\)\\W")
+ (1 font-lock-constant-face nil nil)) ;; $_GET & co
+ '("\\$\\(\\sw+\\)" (1 font-lock-variable-name-face)) ;; $variable
+ '("->\\(\\sw+\\)" (1 font-lock-variable-name-face t t)) ;; ->variable
+ '("->\\(\\sw+\\)\\s-*(" . (1 php-default-face t t)) ;; ->function_call
+ '("\\(\\sw+\\)::\\sw+\\s-*(?" . (1 font-lock-type-face)) ;; class::member
+ '("::\\(\\sw+\\>[^(]\\)" . (1 php-default-face)) ;; class::constant
+ '("\\<\\sw+\\s-*[[(]" . php-default-face) ;; word( or word[
+ '("\\<[0-9]+" . php-default-face) ;; number (also matches word)
+
+ ;; Warn on any words not already fontified
+ '("\\<\\sw+\\>" . font-lock-warning-face)
+
+ ))
+ "Gauchy level highlighting for PHP mode.")
+
+(provide 'php-mode)
+
+;;; php-mode.el ends here