]> git.rkrishnan.org Git - .emacs.d.git/blob - emacs/nxhtml/related/php-mode.el
submodulized .emacs.d setup
[.emacs.d.git] / emacs / nxhtml / related / php-mode.el
1 ;;; php-mode.el --- major mode for editing PHP code
2
3 ;; Copyright (C) 1999, 2000, 2001, 2003, 2004 Turadg Aleahmad
4 ;;               2008 Aaron S. Hawley
5
6 ;; Maintainer: Aaron S. Hawley <ashawley at users.sourceforge.net>
7 ;; Author: Turadg Aleahmad, 1999-2004
8 ;; Keywords: php languages oop
9 ;; Created: 1999-05-17
10 ;; Modified: 2008-11-28 Fri
11 ;; X-URL:   http://php-mode.sourceforge.net/
12
13 (defconst php-mode-version-number "1.5.0-nxhtml-1.94"
14   "PHP Mode version number.")
15
16 ;;; License
17
18 ;; This file is free software; you can redistribute it and/or
19 ;; modify it under the terms of the GNU General Public License
20 ;; as published by the Free Software Foundation; either version 3
21 ;; of the License, or (at your option) any later version.
22
23 ;; This file is distributed in the hope that it will be useful,
24 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
25 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26 ;; GNU General Public License for more details.
27
28 ;; You should have received a copy of the GNU General Public License
29 ;; along with this file; if not, write to the Free Software
30 ;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31 ;; 02110-1301, USA.
32
33 ;;; Usage
34
35 ;; Put this file in your Emacs lisp path (eg. site-lisp) and add to
36 ;; your .emacs file:
37 ;;
38 ;;   (require 'php-mode)
39
40 ;; To use abbrev-mode, add lines like this:
41 ;;   (add-hook 'php-mode-hook
42 ;;     '(lambda () (define-abbrev php-mode-abbrev-table "ex" "extends")))
43
44 ;; To make php-mode compatible with html-mode, see http://php-mode.sf.net
45
46 ;; Many options available under Help:Customize
47 ;; Options specific to php-mode are in
48 ;;  Programming/Languages/Php
49 ;; Since it inherits much functionality from c-mode, look there too
50 ;;  Programming/Languages/C
51
52 ;;; Commentary:
53
54 ;; PHP mode is a major mode for editing PHP 3 and 4 source code.  It's
55 ;; an extension of C mode; thus it inherits all C mode's navigation
56 ;; functionality.  But it colors according to the PHP grammar and indents
57 ;; according to the PEAR coding guidelines.  It also includes a couple
58 ;; handy IDE-type features such as documentation search and a source
59 ;; and class browser.
60
61 ;;; Contributors: (in chronological order)
62
63 ;; Juanjo, Torsten Martinsen, Vinai Kopp, Sean Champ, Doug Marcey,
64 ;; Kevin Blake, Rex McMaster, Mathias Meyer, Boris Folgmann, Roland
65 ;; Rosenfeld, Fred Yankowski, Craig Andrews, John Keller, Ryan
66 ;; Sammartino, ppercot, Valentin Funk, Stig Bakken, Gregory Stark,
67 ;; Chris Morris, Nils Rennebarth, Gerrit Riessen, Eric Mc Sween,
68 ;; Ville Skytta, Giacomo Tesio, Lennart Borgman, Stefan Monnier,
69 ;; Aaron S. Hawley, Ian Eure, Bill Lovett, Dias Badekas, David House
70
71 ;;; Changelog:
72
73 ;; 1.5.0-nxhtml-1.88 (Lennart Borgman)
74 ;;   Don't indent heredoc end mark
75 ;; 1.5.0-nxhtml-1.61 (Lennart Borgman)
76 ;;   Added php-mode-to-use.
77 ;;   Made underscore be part of identifiers.
78 ;;   Remove php-mode-to.
79 ;;   Make the indentation check only on current line.
80 ;;   Warn only once per session about indentation.
81 ;;   Tell if can't complete in `php-complete-function'.
82 ;;   Move back point after checking indentation in
83 ;;   `php-check-html-for-indentation'.
84 ;;   Add `c-at-vsemi-p-fn' etc after advice from Alan Mackenzie.
85 ;;
86 ;; 1.5
87 ;;   Support function keywords like public, private and the ampersand
88 ;;   character for function-based commands.  Support abstract, final,
89 ;;   static, public, private and protected keywords in Imenu.  Fix
90 ;;   reversed order of Imenu entries.  Use font-lock-preprocessor-face
91 ;;   for PHP and ASP tags.  Make php-mode-modified a literal value
92 ;;   rather than a computed string.  Add date and time constants of
93 ;;   PHP. (Dias Badekas) Fix false syntax highlighting of keywords
94 ;;   because of underscore character.  Change HTML indentation warning
95 ;;   to match only HTML at the beginning of the line.  Fix
96 ;;   byte-compiler warnings.  Clean-up whitespace and audited style
97 ;;   consistency of code.  Remove conditional bindings and XEmacs code
98 ;;   that likely does nothing.
99 ;;
100 ;; 1.4
101 ;;   Updated GNU GPL to version 3.  Ported to Emacs 22 (CC mode
102 ;;   5.31). M-x php-mode-version shows version.  Provide end-of-defun
103 ;;   beginning-of-defun functionality. Support add-log library.
104 ;;   Fix __CLASS__ constant (Ian Eure).  Allow imenu to see visibility
105 ;;   declarations -- "private", "public", "protected". (Bill Lovett)
106 ;;
107 ;; 1.3
108 ;;   Changed the definition of # using a tip from Stefan
109 ;;   Monnier to correct highlighting and indentation. (Lennart Borgman)
110 ;;   Changed the highlighting of the HTML part. (Lennart Borgman)
111 ;;
112 ;; See the ChangeLog file included with the source package.
113
114
115 ;;; Code:
116
117 (require 'add-log)
118 (require 'speedbar)
119 (require 'font-lock)
120 (require 'cc-mode)
121 (require 'cc-langs)
122 (require 'custom)
123 (require 'etags)
124 (eval-when-compile
125   (require 'regexp-opt))
126 \f
127 ;; Local variables
128 ;;;###autoload
129 (defgroup php nil
130   "Major mode `php-mode' for editing PHP code."
131   :prefix "php-"
132   :group 'languages)
133
134 (defcustom php-default-face 'default
135   "Default face in `php-mode' buffers."
136   :type 'face
137   :group 'php)
138
139 (defcustom php-speedbar-config t
140   "When set to true automatically configures Speedbar to observe PHP files.
141 Ignores php-file patterns option; fixed to expression \"\\.\\(inc\\|php[s34]?\\)\""
142   :type 'boolean
143   :set (lambda (sym val)
144          (set-default sym val)
145          (if (and val (boundp 'speedbar))
146              (speedbar-add-supported-extension
147               "\\.\\(inc\\|php[s34]?\\|phtml\\)")))
148   :group 'php)
149
150 (defcustom php-mode-speedbar-open nil
151   "Normally `php-mode' starts with the speedbar closed.
152 Turning this on will open it whenever `php-mode' is loaded."
153   :type 'boolean
154   :set (lambda (sym val)
155          (set-default sym val)
156          (when val
157              (speedbar 1)))
158   :group 'php)
159
160 (defvar php-imenu-generic-expression
161  '(
162    ("Private Methods"
163     "^\\s-*\\(?:\\(?:abstract\\|final\\)\\s-+\\)?private\\s-+\\(?:static\\s-+\\)?function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1)
164    ("Protected Methods"
165     "^\\s-*\\(?:\\(?:abstract\\|final\\)\\s-+\\)?protected\\s-+\\(?:static\\s-+\\)?function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1)
166    ("Public Methods"
167     "^\\s-*\\(?:\\(?:abstract\\|final\\)\\s-+\\)?public\\s-+\\(?:static\\s-+\\)?function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1)
168    ("Classes"
169     "^\\s-*class\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*" 1)
170    ("All Functions"
171     "^\\s-*\\(?:\\(?:abstract\\|final\\|private\\|protected\\|public\\|static\\)\\s-+\\)*function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1)
172    )
173  "Imenu generic expression for PHP Mode. See `imenu-generic-expression'."
174  )
175
176 (defcustom php-manual-url "http://www.php.net/manual/en/"
177   "URL at which to find PHP manual.
178 You can replace \"en\" with your ISO language code."
179   :type 'string
180   :group 'php)
181
182 (defcustom php-search-url "http://www.php.net/"
183   "URL at which to search for documentation on a word."
184   :type 'string
185   :group 'php)
186
187 (defcustom php-completion-file ""
188   "Path to the file which contains the function names known to PHP."
189   :type 'string
190   :group 'php)
191
192 (defcustom php-manual-path ""
193   "Path to the directory which contains the PHP manual."
194   :type 'string
195   :group 'php)
196
197 ;;;###autoload
198 (defcustom php-file-patterns '("\\.php[s34]?\\'" "\\.phtml\\'" "\\.inc\\'")
199   "List of file patterns for which to automatically invoke `php-mode'."
200   :type '(repeat (regexp :tag "Pattern"))
201   :set (lambda (sym val)
202          (set-default sym val)
203          (let ((php-file-patterns-temp val))
204            (while php-file-patterns-temp
205              (add-to-list 'auto-mode-alist
206                           (cons (car php-file-patterns-temp) 'php-mode))
207              (setq php-file-patterns-temp (cdr php-file-patterns-temp)))))
208   :group 'php)
209
210 (defcustom php-mode-hook nil
211   "List of functions to be executed on entry to `php-mode'."
212   :type 'hook
213   :group 'php)
214
215 (defcustom php-mode-pear-hook nil
216   "Hook called when a PHP PEAR file is opened with `php-mode'."
217   :type 'hook
218   :group 'php)
219
220 (defcustom php-mode-force-pear nil
221   "Normally PEAR coding rules are enforced only when the filename contains \"PEAR.\"
222 Turning this on will force PEAR rules on all PHP files."
223   :type 'boolean
224   :group 'php)
225 \f
226 (defconst php-mode-modified "2009-08-12"
227   "PHP Mode build date.")
228
229 (defun php-mode-version ()
230   "Display string describing the version of PHP mode."
231   (interactive)
232   (message "PHP mode %s of %s"
233            php-mode-version-number php-mode-modified))
234
235 (defconst php-beginning-of-defun-regexp
236   "^\\s-*\\(?:\\(?:abstract\\|final\\|private\\|protected\\|public\\|static\\)\\s-+\\)*function\\s-+&?\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*("
237   "Regular expression for a PHP function.")
238
239 (defun php-beginning-of-defun (&optional arg)
240   "Move to the beginning of the ARGth PHP function from point.
241 Implements PHP version of `beginning-of-defun-function'."
242   (interactive "p")
243   (let ((arg (or arg 1)))
244     (while (> arg 0)
245       (re-search-backward php-beginning-of-defun-regexp
246                           nil 'noerror)
247       (setq arg (1- arg)))
248     (while (< arg 0)
249       (end-of-line 1)
250       (let ((opoint (point)))
251         (beginning-of-defun 1)
252         (forward-list 2)
253         (forward-line 1)
254         (if (eq opoint (point))
255             (re-search-forward php-beginning-of-defun-regexp
256                                nil 'noerror))
257         (setq arg (1+ arg))))))
258
259 (defun php-end-of-defun (&optional arg)
260   "Move the end of the ARGth PHP function from point.
261 Implements PHP befsion of `end-of-defun-function'
262
263 See `php-beginning-of-defun'."
264   (interactive "p")
265   (php-beginning-of-defun (- (or arg 1))))
266
267 \f
268 (defvar php-warned-bad-indent nil)
269 ;;(make-variable-buffer-local 'php-warned-bad-indent)
270
271 ;; Do it but tell it is not good if html tags in buffer.
272 (defun php-check-html-for-indentation ()
273   (let ((html-tag-re "^\\s-*</?\\sw+.*?>")
274         (here (point)))
275     (goto-char (line-beginning-position))
276     (if (or (when (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode)
277             ;; Fix-me: no idea how to check for mmm or multi-mode
278             (save-match-data
279               (not (or (re-search-forward html-tag-re (line-end-position) t)
280                        (re-search-backward html-tag-re (line-beginning-position) t)))))
281         (progn
282           (goto-char here)
283           t)
284       (goto-char here)
285       (setq php-warned-bad-indent t)
286       ;;(setq php-warned-bad-indent nil)
287       (let* ((known-multi-libs '(("mumamo" mumamo (lambda () (nxhtml-mumamo)))
288                                  ("mmm-mode" mmm-mode (lambda () (mmm-mode 1)))
289                                  ("multi-mode" multi-mode (lambda () (multi-mode 1)))))
290              (known-names (mapcar (lambda (lib) (car lib)) known-multi-libs))
291              (available-multi-libs (delq nil
292                                          (mapcar
293                                           (lambda (lib)
294                                             (when (locate-library (car lib)) lib))
295                                           known-multi-libs)))
296              (available-names (mapcar (lambda (lib) (car lib)) available-multi-libs))
297              (base-msg
298               (concat
299                "Indentation fails badly with mixed HTML/PHP in the HTML part in
300 plaín `php-mode'.  To get indentation to work you must use an
301 Emacs library that supports 'multiple major modes' in a buffer.
302 Parts of the buffer will then be in `php-mode' and parts in for
303 example `html-mode'.  Known such libraries are:\n\t"
304                (mapconcat 'identity known-names ", ")
305                "\n"
306                (if available-multi-libs
307                    (concat
308                     "You have these available in your `load-path':\n\t"
309                     (mapconcat 'identity available-names ", ")
310                     "\n\n"
311                     "Do you want to turn any of those on? ")
312                  "You do not have any of those in your `load-path'.")))
313              (is-using-multi
314               (catch 'is-using
315                 (dolist (lib available-multi-libs)
316                   (when (and (boundp (cadr lib))
317                              (symbol-value (cadr lib)))
318                     (throw 'is-using t))))))
319         (unless is-using-multi
320           (if available-multi-libs
321               (if (not (y-or-n-p base-msg))
322                   (message "Did not do indentation, but you can try again now if you want")
323                 (let* ((name
324                         (if (= 1 (length available-multi-libs))
325                             (car available-names)
326                           ;; Minibuffer window is more than one line, fix that first:
327                           (message "")
328                           (completing-read "Choose multiple major mode support library: "
329                                            available-names nil t
330                                            (car available-names)
331                                            '(available-names . 1)
332                                            )))
333                        (mode (when name
334                                (caddr (assoc name available-multi-libs)))))
335                   (when mode
336                     ;; Minibuffer window is more than one line, fix that first:
337                     (message "")
338                     (load name)
339                     (funcall mode))))
340             (lwarn 'php-indent :warning base-msg)))
341         nil))))
342
343 (defun php-cautious-indent-region (start end &optional quiet)
344   (if (or php-warned-bad-indent
345           (php-check-html-for-indentation))
346       (funcall 'c-indent-region start end quiet)))
347
348 (defun php-cautious-indent-line ()
349   (if (or php-warned-bad-indent
350           (php-check-html-for-indentation))
351       (let ((here (point))
352             doit)
353         (move-beginning-of-line nil)
354         ;; Don't indent heredoc end mark
355         (save-match-data
356           (unless (looking-at "[a-zA-Z0-9_]+;\n")
357             (setq doit t)))
358         (goto-char here)
359         (when doit
360           (funcall 'c-indent-line)))))
361
362 (defconst php-tags '("<?php" "?>" "<?" "<?="))
363 (defconst php-tags-key (regexp-opt php-tags))
364
365 (defconst php-block-stmt-1-kwds '("do" "else" "finally" "try"))
366 (defconst php-block-stmt-2-kwds
367   '("for" "if" "while" "switch" "foreach" "elseif"  "catch all"))
368
369 (defconst php-block-stmt-1-key
370   (regexp-opt php-block-stmt-1-kwds))
371 (defconst php-block-stmt-2-key
372   (regexp-opt php-block-stmt-2-kwds))
373
374 (defconst php-class-decl-kwds '("class" "interface"))
375
376 (defconst php-class-key
377   (concat
378    "\\(" (regexp-opt php-class-decl-kwds) "\\)\\s-+"
379    (c-lang-const c-symbol-key c)                ;; Class name.
380    "\\(\\s-+extends\\s-+" (c-lang-const c-symbol-key c) "\\)?" ;; Name of superclass.
381    "\\(\\s-+implements\\s-+[^{]+{\\)?")) ;; List of any adopted protocols.
382
383
384 (defun php-c-at-vsemi-p (&optional pos)
385   "Return t on html lines (including php region border), otherwise nil.
386 POS is a position on the line in question.
387
388 This is was done due to the problem reported here:
389
390   URL `https://answers.launchpad.net/nxhtml/+question/43320'"
391   (setq pos (or pos (point)))
392   (let ((here (point))
393         ret)
394   (save-match-data
395     (goto-char pos)
396     (beginning-of-line)
397     (setq ret (looking-at
398                (rx
399                 (or (seq
400                      bol
401                      (0+ space)
402                      "<"
403                      (in "a-z\\?"))
404                     (seq
405                      ;;(0+ anything)
406                      (0+ not-newline)
407                      (in "a-z\\?")
408                      ">"
409                      (0+ space)
410                      eol))))))
411   (goto-char here)
412   ret))
413
414 (defun php-c-vsemi-status-unknown-p ()
415   "See `php-c-at-vsemi-p'."
416   )
417
418 ;;;###autoload
419 (define-derived-mode php-mode c-mode "PHP"
420   "Major mode for editing PHP code.\n\n\\{php-mode-map}"
421   (c-add-language 'php-mode 'c-mode)
422
423 ;; PHP doesn't have C-style macros.
424 ;; HACK: Overwrite this syntax with rules to match <?php and others.
425 ;;   (c-lang-defconst c-opt-cpp-start php php-tags-key)
426 ;;   (c-lang-defvar c-opt-cpp-start (c-lang-const c-opt-cpp-start))
427   (set (make-local-variable 'c-opt-cpp-start) php-tags-key)
428 ;;   (c-lang-defconst c-opt-cpp-start php php-tags-key)
429 ;;   (c-lang-defvar c-opt-cpp-start (c-lang-const c-opt-cpp-start))
430   (set (make-local-variable 'c-opt-cpp-prefix) php-tags-key)
431
432   (c-set-offset 'cpp-macro 0)
433   
434 ;;   (c-lang-defconst c-block-stmt-1-kwds php php-block-stmt-1-kwds)
435 ;;   (c-lang-defvar c-block-stmt-1-kwds (c-lang-const c-block-stmt-1-kwds))
436   (set (make-local-variable 'c-block-stmt-1-key) php-block-stmt-1-key)
437
438 ;;   (c-lang-defconst c-block-stmt-2-kwds php php-block-stmt-2-kwds)
439 ;;   (c-lang-defvar c-block-stmt-2-kwds (c-lang-const c-block-stmt-2-kwds))
440   (set (make-local-variable 'c-block-stmt-2-key) php-block-stmt-2-key)
441
442   ;; Specify that cc-mode recognize Javadoc comment style
443   (set (make-local-variable 'c-doc-comment-style)
444     '((php-mode . javadoc)))
445
446 ;;   (c-lang-defconst c-class-decl-kwds
447 ;;     php php-class-decl-kwds)
448   (set (make-local-variable 'c-class-key) php-class-key)
449
450   (make-local-variable 'font-lock-defaults)
451   (setq font-lock-defaults
452         '((php-font-lock-keywords-1
453            php-font-lock-keywords-2
454                ;; Comment-out the next line if the font-coloring is too
455                ;; extreme/ugly for you.
456            php-font-lock-keywords-3)
457           nil                               ; KEYWORDS-ONLY
458           t                                 ; CASE-FOLD
459           (("_" . "w"))                    ; SYNTAX-ALIST
460           nil))                             ; SYNTAX-BEGIN
461   (modify-syntax-entry ?# "< b" php-mode-syntax-table)
462   ;;(modify-syntax-entry ?_ "w" php-mode-syntax-table)
463
464   ;; Electric behaviour must be turned off, they do not work since
465   ;; they can not find the correct syntax in embedded PHP.
466   ;;
467   ;; Seems to work with narrowing so let it be on if the user prefers it.
468   ;;(setq c-electric-flag nil)
469
470   (setq font-lock-maximum-decoration t
471         case-fold-search t              ; PHP vars are case-sensitive
472         imenu-generic-expression php-imenu-generic-expression)
473
474   ;; Do not force newline at end of file.  Such newlines can cause
475   ;; trouble if the PHP file is included in another file before calls
476   ;; to header() or cookie().
477   (set (make-local-variable 'require-final-newline) nil)
478   (set (make-local-variable 'next-line-add-newlines) nil)
479
480   ;; PEAR coding standards
481   (add-hook 'php-mode-pear-hook
482             (lambda ()
483               (set (make-local-variable 'tab-width) 4)
484               (set (make-local-variable 'c-basic-offset) 4)
485               (set (make-local-variable 'indent-tabs-mode) nil)
486               (c-set-offset 'block-open' - )
487               (c-set-offset 'block-close' 0 )) nil t)
488
489   (if (or php-mode-force-pear
490           (and (stringp buffer-file-name)
491                (string-match "PEAR\\|pear"
492                              (buffer-file-name))
493                (string-match "\\.php$" (buffer-file-name))))
494       (run-hooks 'php-mode-pear-hook))
495
496   (setq indent-line-function 'php-cautious-indent-line)
497   (setq indent-region-function 'php-cautious-indent-region)
498   (setq c-special-indent-hook nil)
499   (setq c-at-vsemi-p-fn 'php-c-at-vsemi-p)
500   (setq c-vsemi-status-unknown-p 'php-c-vsemi-status-unknown-p)
501
502   (set (make-local-variable 'syntax-begin-function)
503        'c-beginning-of-syntax)
504   (set (make-local-variable 'beginning-of-defun-function)
505        'php-beginning-of-defun)
506   (set (make-local-variable 'end-of-defun-function)
507        'php-end-of-defun)
508   (set (make-local-variable 'open-paren-in-column-0-is-defun-start)
509        nil)
510   (set (make-local-variable 'defun-prompt-regexp)
511        "^\\s-*function\\s-+&?\\s-*\\(\\(\\sw\\|\\s_\\)+\\)\\s-*")
512   (set (make-local-variable 'add-log-current-defun-header-regexp)
513        php-beginning-of-defun-regexp)
514
515   (run-hooks 'php-mode-hook))
516 \f
517 ;; Make a menu keymap (with a prompt string)
518 ;; and make it the menu bar item's definition.
519 (define-key php-mode-map [menu-bar] (make-sparse-keymap))
520 (define-key php-mode-map [menu-bar php]
521   (cons "PHP" (make-sparse-keymap "PHP")))
522
523 ;; Define specific subcommands in this menu.
524 (define-key php-mode-map [menu-bar php complete-function]
525   '("Complete function name" . php-complete-function))
526 (define-key php-mode-map
527   [menu-bar php browse-manual]
528   '("Browse manual" . php-browse-manual))
529 (define-key php-mode-map
530   [menu-bar php search-documentation]
531   '("Search documentation" . php-search-documentation))
532 \f
533 ;; Define function name completion function
534 (defvar php-completion-table nil
535   "Obarray of tag names defined in current tags table and functions known to PHP.")
536
537 (defun php-complete-function ()
538   "Perform function completion on the text around point.
539 Completes to the set of names listed in the current tags table
540 and the standard php functions.
541 The string to complete is chosen in the same way as the default
542 for \\[find-tag] (which see)."
543   (interactive)
544   (let ((pattern (php-get-pattern))
545         beg
546         completion
547         (php-functions (php-completion-table)))
548     (if (not pattern) (message "Nothing to complete")
549         (if (not (search-backward pattern nil t))
550             (message "Can't complete here")
551           (setq beg (point))
552           (forward-char (length pattern))
553           (setq completion (try-completion pattern php-functions nil))
554           (cond ((eq completion t))
555                 ((null completion)
556                  (message "Can't find completion for \"%s\"" pattern)
557                  (ding))
558                 ((not (string= pattern completion))
559                  (delete-region beg (point))
560                  (insert completion))
561                 (t
562                  (message "Making completion list...")
563                  (with-output-to-temp-buffer "*Completions*"
564                    (display-completion-list
565                     (all-completions pattern php-functions)))
566                  (message "Making completion list...%s" "done")))))))
567
568 (defun php-completion-table ()
569   "Build variable `php-completion-table' on demand.
570 The table includes the PHP functions and the tags from the
571 current `tags-file-name'."
572   (or (and tags-file-name
573            (save-excursion (tags-verify-table tags-file-name))
574            php-completion-table)
575       (let ((tags-table
576              (if (and tags-file-name
577                       (functionp 'etags-tags-completion-table))
578                  (with-current-buffer (get-file-buffer tags-file-name)
579                    (etags-tags-completion-table))
580                nil))
581             (php-table
582              (cond ((and (not (string= "" php-completion-file))
583                          (file-readable-p php-completion-file))
584                     (php-build-table-from-file php-completion-file))
585                    (php-manual-path
586                     (php-build-table-from-path php-manual-path))
587                    (t nil))))
588         (unless (or php-table tags-table)
589           (error
590            (concat "No TAGS file active nor are "
591                    "`php-completion-file' or `php-manual-path' set")))
592         (when tags-table
593           ;; Combine the tables.
594           (mapatoms (lambda (sym) (intern (symbol-name sym) php-table))
595                     tags-table))
596         (setq php-completion-table php-table))))
597
598 (defun php-build-table-from-file (filename)
599   (let ((table (make-vector 1022 0))
600         (buf (find-file-noselect filename)))
601     (save-excursion
602       (set-buffer buf)
603       (goto-char (point-min))
604       (while (re-search-forward
605               "^\\([-a-zA-Z0-9_.]+\\)\n"
606               nil t)
607         (intern (buffer-substring (match-beginning 1) (match-end 1))
608                 table)))
609     (kill-buffer buf)
610     table))
611
612 (defun php-build-table-from-path (path)
613   (let ((table (make-vector 1022 0))
614         (files (directory-files
615                 path
616                 nil
617                 "^function\\..+\\.html$")))
618     (mapc (lambda (file)
619             (string-match "\\.\\([-a-zA-Z_0-9]+\\)\\.html$" file)
620             (intern
621              (replace-regexp-in-string
622               "-" "_" (substring file (match-beginning 1) (match-end 1)) t)
623              table))
624           files)
625     table))
626
627 ;; Find the pattern we want to complete
628 ;; find-tag-default from GNU Emacs etags.el
629 (defun php-get-pattern ()
630   (save-excursion
631     (while (looking-at "\\sw\\|\\s_")
632       (forward-char 1))
633     (if (or (re-search-backward "\\sw\\|\\s_"
634                                 (save-excursion (beginning-of-line) (point))
635                                 t)
636             (re-search-forward "\\(\\sw\\|\\s_\\)+"
637                                (save-excursion (end-of-line) (point))
638                                t))
639         (progn (goto-char (match-end 0))
640                (buffer-substring-no-properties
641                 (point)
642                 (progn (forward-sexp -1)
643                        (while (looking-at "\\s'")
644                          (forward-char 1))
645                        (point))))
646       nil)))
647
648 (defun php-show-arglist ()
649   (interactive)
650   (let* ((tagname (php-get-pattern))
651          (buf (find-tag-noselect tagname nil nil))
652          arglist)
653     (save-excursion
654       (set-buffer buf)
655       (goto-char (point-min))
656       (when (re-search-forward
657              (format "function\\s-+%s\\s-*(\\([^{]*\\))" tagname)
658              nil t)
659         (setq arglist (buffer-substring-no-properties
660                        (match-beginning 1) (match-end 1)))))
661     (if arglist
662         (message "Arglist for %s: %s" tagname arglist)
663         (message "Unknown function: %s" tagname))))
664 \f
665 ;; Define function documentation function
666 (defun php-search-documentation ()
667   "Search PHP documentation for the word at point."
668   (interactive)
669   (browse-url (concat php-search-url (current-word t))))
670
671 ;; Define function for browsing manual
672 (defun php-browse-manual ()
673   "Bring up manual for PHP."
674   (interactive)
675   (browse-url php-manual-url))
676
677 ;; Define shortcut
678 (define-key php-mode-map
679   "\C-c\C-f"
680   'php-search-documentation)
681
682 ;; Define shortcut
683 (define-key php-mode-map
684   [(meta tab)]
685   'php-complete-function)
686
687 ;; Define shortcut
688 (define-key php-mode-map
689   "\C-c\C-m"
690   'php-browse-manual)
691
692 ;; Define shortcut
693 (define-key php-mode-map
694   '[(control .)]
695   'php-show-arglist)
696
697 ;; Use the Emacs standard indentation binding. This may upset c-mode
698 ;; which does not follow this at the moment, but I see no better
699 ;; choice.
700 (define-key php-mode-map [?\t] 'indent-for-tab-command)
701
702 \f
703 (defconst php-constants
704   (eval-when-compile
705     (regexp-opt
706      '(;; core constants
707        "__LINE__" "__FILE__"
708        "__FUNCTION__" "__CLASS__" "__METHOD__"
709        "PHP_OS" "PHP_VERSION"
710        "TRUE" "FALSE" "NULL"
711        "E_ERROR" "E_NOTICE" "E_PARSE" "E_WARNING" "E_ALL" "E_STRICT"
712        "E_USER_ERROR" "E_USER_WARNING" "E_USER_NOTICE"
713        "DEFAULT_INCLUDE_PATH" "PEAR_INSTALL_DIR" "PEAR_EXTENSION_DIR"
714        "PHP_BINDIR" "PHP_LIBDIR" "PHP_DATADIR" "PHP_SYSCONFDIR"
715        "PHP_LOCALSTATEDIR" "PHP_CONFIG_FILE_PATH"
716        "PHP_EOL"
717
718        ;; date and time constants
719        "DATE_ATOM" "DATE_COOKIE" "DATE_ISO8601"
720        "DATE_RFC822" "DATE_RFC850" "DATE_RFC1036" "DATE_RFC1123"
721        "DATE_RFC2822" "DATE_RFC3339"
722        "DATE_RSS" "DATE_W3C"
723
724        ;; from ext/standard:
725        "EXTR_OVERWRITE" "EXTR_SKIP" "EXTR_PREFIX_SAME"
726        "EXTR_PREFIX_ALL" "EXTR_PREFIX_INVALID" "SORT_ASC" "SORT_DESC"
727        "SORT_REGULAR" "SORT_NUMERIC" "SORT_STRING" "ASSERT_ACTIVE"
728        "ASSERT_CALLBACK" "ASSERT_BAIL" "ASSERT_WARNING"
729        "ASSERT_QUIET_EVAL" "CONNECTION_ABORTED" "CONNECTION_NORMAL"
730        "CONNECTION_TIMEOUT" "M_E" "M_LOG2E" "M_LOG10E" "M_LN2"
731        "M_LN10" "M_PI" "M_PI_2" "M_PI_4" "M_1_PI" "M_2_PI"
732        "M_2_SQRTPI" "M_SQRT2" "M_SQRT1_2" "CRYPT_SALT_LENGTH"
733        "CRYPT_STD_DES" "CRYPT_EXT_DES" "CRYPT_MD5" "CRYPT_BLOWFISH"
734        "DIRECTORY_SEPARATOR" "SEEK_SET" "SEEK_CUR" "SEEK_END"
735        "LOCK_SH" "LOCK_EX" "LOCK_UN" "LOCK_NB" "HTML_SPECIALCHARS"
736        "HTML_ENTITIES" "ENT_COMPAT" "ENT_QUOTES" "ENT_NOQUOTES"
737        "INFO_GENERAL" "INFO_CREDITS" "INFO_CONFIGURATION"
738        "INFO_ENVIRONMENT" "INFO_VARIABLES" "INFO_LICENSE" "INFO_ALL"
739        "CREDITS_GROUP" "CREDITS_GENERAL" "CREDITS_SAPI"
740        "CREDITS_MODULES" "CREDITS_DOCS" "CREDITS_FULLPAGE"
741        "CREDITS_QA" "CREDITS_ALL" "PHP_OUTPUT_HANDLER_START"
742        "PHP_OUTPUT_HANDLER_CONT" "PHP_OUTPUT_HANDLER_END"
743        "STR_PAD_LEFT" "STR_PAD_RIGHT" "STR_PAD_BOTH"
744        "PATHINFO_DIRNAME" "PATHINFO_BASENAME" "PATHINFO_EXTENSION"
745        "CHAR_MAX" "LC_CTYPE" "LC_NUMERIC" "LC_TIME" "LC_COLLATE"
746        "LC_MONETARY" "LC_ALL" "LC_MESSAGES" "LOG_EMERG" "LOG_ALERT"
747        "LOG_CRIT" "LOG_ERR" "LOG_WARNING" "LOG_NOTICE" "LOG_INFO"
748        "LOG_DEBUG" "LOG_KERN" "LOG_USER" "LOG_MAIL" "LOG_DAEMON"
749        "LOG_AUTH" "LOG_SYSLOG" "LOG_LPR" "LOG_NEWS" "LOG_UUCP"
750        "LOG_CRON" "LOG_AUTHPRIV" "LOG_LOCAL0" "LOG_LOCAL1"
751        "LOG_LOCAL2" "LOG_LOCAL3" "LOG_LOCAL4" "LOG_LOCAL5"
752        "LOG_LOCAL6" "LOG_LOCAL7" "LOG_PID" "LOG_CONS" "LOG_ODELAY"
753        "LOG_NDELAY" "LOG_NOWAIT" "LOG_PERROR"
754
755        ;; Disabled by default because they slow buffer loading
756        ;; If you have use for them, uncomment the strings
757        ;; that you want colored.
758        ;; To compile, you may have to increase 'max-specpdl-size'
759
760        ;; from other bundled extensions:
761 ;        "CAL_EASTER_TO_xxx" "VT_NULL" "VT_EMPTY" "VT_UI1" "VT_I2"
762 ;        "VT_I4" "VT_R4" "VT_R8" "VT_BOOL" "VT_ERROR" "VT_CY" "VT_DATE"
763 ;        "VT_BSTR" "VT_DECIMAL" "VT_UNKNOWN" "VT_DISPATCH" "VT_VARIANT"
764 ;        "VT_I1" "VT_UI2" "VT_UI4" "VT_INT" "VT_UINT" "VT_ARRAY"
765 ;        "VT_BYREF" "CP_ACP" "CP_MACCP" "CP_OEMCP" "CP_SYMBOL"
766 ;        "CP_THREAD_ACP" "CP_UTF7" "CP_UTF8" "CPDF_PM_NONE"
767 ;        "CPDF_PM_OUTLINES" "CPDF_PM_THUMBS" "CPDF_PM_FULLSCREEN"
768 ;        "CPDF_PL_SINGLE" "CPDF_PL_1COLUMN" "CPDF_PL_2LCOLUMN"
769 ;        "CPDF_PL_2RCOLUMN" "CURLOPT_PORT" "CURLOPT_FILE"
770 ;        "CURLOPT_INFILE" "CURLOPT_INFILESIZE" "CURLOPT_URL"
771 ;        "CURLOPT_PROXY" "CURLOPT_VERBOSE" "CURLOPT_HEADER"
772 ;        "CURLOPT_HTTPHEADER" "CURLOPT_NOPROGRESS" "CURLOPT_NOBODY"
773 ;        "CURLOPT_FAILONERROR" "CURLOPT_UPLOAD" "CURLOPT_POST"
774 ;        "CURLOPT_FTPLISTONLY" "CURLOPT_FTPAPPEND" "CURLOPT_NETRC"
775 ;        "CURLOPT_FOLLOWLOCATION" "CURLOPT_FTPASCII" "CURLOPT_PUT"
776 ;        "CURLOPT_MUTE" "CURLOPT_USERPWD" "CURLOPT_PROXYUSERPWD"
777 ;        "CURLOPT_RANGE" "CURLOPT_TIMEOUT" "CURLOPT_POSTFIELDS"
778 ;        "CURLOPT_REFERER" "CURLOPT_USERAGENT" "CURLOPT_FTPPORT"
779 ;        "CURLOPT_LOW_SPEED_LIMIT" "CURLOPT_LOW_SPEED_TIME"
780 ;        "CURLOPT_RESUME_FROM" "CURLOPT_COOKIE" "CURLOPT_SSLCERT"
781 ;        "CURLOPT_SSLCERTPASSWD" "CURLOPT_WRITEHEADER"
782 ;        "CURLOPT_COOKIEFILE" "CURLOPT_SSLVERSION"
783 ;        "CURLOPT_TIMECONDITION" "CURLOPT_TIMEVALUE"
784 ;        "CURLOPT_CUSTOMREQUEST" "CURLOPT_STDERR" "CURLOPT_TRANSFERTEXT"
785 ;        "CURLOPT_RETURNTRANSFER" "CURLOPT_QUOTE" "CURLOPT_POSTQUOTE"
786 ;        "CURLOPT_INTERFACE" "CURLOPT_KRB4LEVEL"
787 ;        "CURLOPT_HTTPPROXYTUNNEL" "CURLOPT_FILETIME"
788 ;        "CURLOPT_WRITEFUNCTION" "CURLOPT_READFUNCTION"
789 ;        "CURLOPT_PASSWDFUNCTION" "CURLOPT_HEADERFUNCTION"
790 ;        "CURLOPT_MAXREDIRS" "CURLOPT_MAXCONNECTS" "CURLOPT_CLOSEPOLICY"
791 ;        "CURLOPT_FRESH_CONNECT" "CURLOPT_FORBID_REUSE"
792 ;        "CURLOPT_RANDOM_FILE" "CURLOPT_EGDSOCKET"
793 ;        "CURLOPT_CONNECTTIMEOUT" "CURLOPT_SSL_VERIFYPEER"
794 ;        "CURLOPT_CAINFO" "CURLOPT_BINARYTRANSER"
795 ;        "CURLCLOSEPOLICY_LEAST_RECENTLY_USED" "CURLCLOSEPOLICY_OLDEST"
796 ;        "CURLINFO_EFFECTIVE_URL" "CURLINFO_HTTP_CODE"
797 ;        "CURLINFO_HEADER_SIZE" "CURLINFO_REQUEST_SIZE"
798 ;        "CURLINFO_TOTAL_TIME" "CURLINFO_NAMELOOKUP_TIME"
799 ;        "CURLINFO_CONNECT_TIME" "CURLINFO_PRETRANSFER_TIME"
800 ;        "CURLINFO_SIZE_UPLOAD" "CURLINFO_SIZE_DOWNLOAD"
801 ;        "CURLINFO_SPEED_DOWNLOAD" "CURLINFO_SPEED_UPLOAD"
802 ;        "CURLINFO_FILETIME" "CURLE_OK" "CURLE_UNSUPPORTED_PROTOCOL"
803 ;        "CURLE_FAILED_INIT" "CURLE_URL_MALFORMAT"
804 ;        "CURLE_URL_MALFORMAT_USER" "CURLE_COULDNT_RESOLVE_PROXY"
805 ;        "CURLE_COULDNT_RESOLVE_HOST" "CURLE_COULDNT_CONNECT"
806 ;        "CURLE_FTP_WEIRD_SERVER_REPLY" "CURLE_FTP_ACCESS_DENIED"
807 ;        "CURLE_FTP_USER_PASSWORD_INCORRECT"
808 ;        "CURLE_FTP_WEIRD_PASS_REPLY" "CURLE_FTP_WEIRD_USER_REPLY"
809 ;        "CURLE_FTP_WEIRD_PASV_REPLY" "CURLE_FTP_WEIRD_227_FORMAT"
810 ;        "CURLE_FTP_CANT_GET_HOST" "CURLE_FTP_CANT_RECONNECT"
811 ;        "CURLE_FTP_COULDNT_SET_BINARY" "CURLE_PARTIAL_FILE"
812 ;        "CURLE_FTP_COULDNT_RETR_FILE" "CURLE_FTP_WRITE_ERROR"
813 ;        "CURLE_FTP_QUOTE_ERROR" "CURLE_HTTP_NOT_FOUND"
814 ;        "CURLE_WRITE_ERROR" "CURLE_MALFORMAT_USER"
815 ;        "CURLE_FTP_COULDNT_STOR_FILE" "CURLE_READ_ERROR"
816 ;        "CURLE_OUT_OF_MEMORY" "CURLE_OPERATION_TIMEOUTED"
817 ;        "CURLE_FTP_COULDNT_SET_ASCII" "CURLE_FTP_PORT_FAILED"
818 ;        "CURLE_FTP_COULDNT_USE_REST" "CURLE_FTP_COULDNT_GET_SIZE"
819 ;        "CURLE_HTTP_RANGE_ERROR" "CURLE_HTTP_POST_ERROR"
820 ;        "CURLE_SSL_CONNECT_ERROR" "CURLE_FTP_BAD_DOWNLOAD_RESUME"
821 ;        "CURLE_FILE_COULDNT_READ_FILE" "CURLE_LDAP_CANNOT_BIND"
822 ;        "CURLE_LDAP_SEARCH_FAILED" "CURLE_LIBRARY_NOT_FOUND"
823 ;        "CURLE_FUNCTION_NOT_FOUND" "CURLE_ABORTED_BY_CALLBACK"
824 ;        "CURLE_BAD_FUNCTION_ARGUMENT" "CURLE_BAD_CALLING_ORDER"
825 ;        "CURLE_HTTP_PORT_FAILED" "CURLE_BAD_PASSWORD_ENTERED"
826 ;        "CURLE_TOO_MANY_REDIRECTS" "CURLE_UNKOWN_TELNET_OPTION"
827 ;        "CURLE_TELNET_OPTION_SYNTAX" "CURLE_ALREADY_COMPLETE"
828 ;        "DBX_MYSQL" "DBX_ODBC" "DBX_PGSQL" "DBX_MSSQL" "DBX_PERSISTENT"
829 ;        "DBX_RESULT_INFO" "DBX_RESULT_INDEX" "DBX_RESULT_ASSOC"
830 ;        "DBX_CMP_TEXT" "DBX_CMP_NUMBER" "XML_ELEMENT_NODE"
831 ;        "XML_ATTRIBUTE_NODE" "XML_TEXT_NODE" "XML_CDATA_SECTION_NODE"
832 ;        "XML_ENTITY_REF_NODE" "XML_ENTITY_NODE" "XML_PI_NODE"
833 ;        "XML_COMMENT_NODE" "XML_DOCUMENT_NODE" "XML_DOCUMENT_TYPE_NODE"
834 ;        "XML_DOCUMENT_FRAG_NODE" "XML_NOTATION_NODE"
835 ;        "XML_HTML_DOCUMENT_NODE" "XML_DTD_NODE" "XML_ELEMENT_DECL_NODE"
836 ;        "XML_ATTRIBUTE_DECL_NODE" "XML_ENTITY_DECL_NODE"
837 ;        "XML_NAMESPACE_DECL_NODE" "XML_GLOBAL_NAMESPACE"
838 ;        "XML_LOCAL_NAMESPACE" "XML_ATTRIBUTE_CDATA" "XML_ATTRIBUTE_ID"
839 ;        "XML_ATTRIBUTE_IDREF" "XML_ATTRIBUTE_IDREFS"
840 ;        "XML_ATTRIBUTE_ENTITY" "XML_ATTRIBUTE_NMTOKEN"
841 ;        "XML_ATTRIBUTE_NMTOKENS" "XML_ATTRIBUTE_ENUMERATION"
842 ;        "XML_ATTRIBUTE_NOTATION" "XPATH_UNDEFINED" "XPATH_NODESET"
843 ;        "XPATH_BOOLEAN" "XPATH_NUMBER" "XPATH_STRING" "XPATH_POINT"
844 ;        "XPATH_RANGE" "XPATH_LOCATIONSET" "XPATH_USERS" "FBSQL_ASSOC"
845 ;        "FBSQL_NUM" "FBSQL_BOTH" "FDFValue" "FDFStatus" "FDFFile"
846 ;        "FDFID" "FDFFf" "FDFSetFf" "FDFClearFf" "FDFFlags" "FDFSetF"
847 ;        "FDFClrF" "FDFAP" "FDFAS" "FDFAction" "FDFAA" "FDFAPRef"
848 ;        "FDFIF" "FDFEnter" "FDFExit" "FDFDown" "FDFUp" "FDFFormat"
849 ;        "FDFValidate" "FDFKeystroke" "FDFCalculate"
850 ;        "FRIBIDI_CHARSET_UTF8" "FRIBIDI_CHARSET_8859_6"
851 ;        "FRIBIDI_CHARSET_8859_8" "FRIBIDI_CHARSET_CP1255"
852 ;        "FRIBIDI_CHARSET_CP1256" "FRIBIDI_CHARSET_ISIRI_3342"
853 ;        "FTP_ASCII" "FTP_BINARY" "FTP_IMAGE" "FTP_TEXT" "IMG_GIF"
854 ;        "IMG_JPG" "IMG_JPEG" "IMG_PNG" "IMG_WBMP" "IMG_COLOR_TILED"
855 ;        "IMG_COLOR_STYLED" "IMG_COLOR_BRUSHED"
856 ;        "IMG_COLOR_STYLEDBRUSHED" "IMG_COLOR_TRANSPARENT"
857 ;        "IMG_ARC_ROUNDED" "IMG_ARC_PIE" "IMG_ARC_CHORD"
858 ;        "IMG_ARC_NOFILL" "IMG_ARC_EDGED" "GMP_ROUND_ZERO"
859 ;        "GMP_ROUND_PLUSINF" "GMP_ROUND_MINUSINF" "HW_ATTR_LANG"
860 ;        "HW_ATTR_NR" "HW_ATTR_NONE" "IIS_READ" "IIS_WRITE"
861 ;        "IIS_EXECUTE" "IIS_SCRIPT" "IIS_ANONYMOUS" "IIS_BASIC"
862 ;        "IIS_NTLM" "NIL" "OP_DEBUG" "OP_READONLY" "OP_ANONYMOUS"
863 ;        "OP_SHORTCACHE" "OP_SILENT" "OP_PROTOTYPE" "OP_HALFOPEN"
864 ;        "OP_EXPUNGE" "OP_SECURE" "CL_EXPUNGE" "FT_UID" "FT_PEEK"
865 ;        "FT_NOT" "FT_INTERNAL" "FT_PREFETCHTEXT" "ST_UID" "ST_SILENT"
866 ;        "ST_SET" "CP_UID" "CP_MOVE" "SE_UID" "SE_FREE" "SE_NOPREFETCH"
867 ;        "SO_FREE" "SO_NOSERVER" "SA_MESSAGES" "SA_RECENT" "SA_UNSEEN"
868 ;        "SA_UIDNEXT" "SA_UIDVALIDITY" "SA_ALL" "LATT_NOINFERIORS"
869 ;        "LATT_NOSELECT" "LATT_MARKED" "LATT_UNMARKED" "SORTDATE"
870 ;        "SORTARRIVAL" "SORTFROM" "SORTSUBJECT" "SORTTO" "SORTCC"
871 ;        "SORTSIZE" "TYPETEXT" "TYPEMULTIPART" "TYPEMESSAGE"
872 ;        "TYPEAPPLICATION" "TYPEAUDIO" "TYPEIMAGE" "TYPEVIDEO"
873 ;        "TYPEOTHER" "ENC7BIT" "ENC8BIT" "ENCBINARY" "ENCBASE64"
874 ;        "ENCQUOTEDPRINTABLE" "ENCOTHER" "INGRES_ASSOC" "INGRES_NUM"
875 ;        "INGRES_BOTH" "IBASE_DEFAULT" "IBASE_TEXT" "IBASE_UNIXTIME"
876 ;        "IBASE_READ" "IBASE_COMMITTED" "IBASE_CONSISTENCY"
877 ;        "IBASE_NOWAIT" "IBASE_TIMESTAMP" "IBASE_DATE" "IBASE_TIME"
878 ;        "LDAP_DEREF_NEVER" "LDAP_DEREF_SEARCHING" "LDAP_DEREF_FINDING"
879 ;        "LDAP_DEREF_ALWAYS" "LDAP_OPT_DEREF" "LDAP_OPT_SIZELIMIT"
880 ;        "LDAP_OPT_TIMELIMIT" "LDAP_OPT_PROTOCOL_VERSION"
881 ;        "LDAP_OPT_ERROR_NUMBER" "LDAP_OPT_REFERRALS" "LDAP_OPT_RESTART"
882 ;        "LDAP_OPT_HOST_NAME" "LDAP_OPT_ERROR_STRING"
883 ;        "LDAP_OPT_MATCHED_DN" "LDAP_OPT_SERVER_CONTROLS"
884 ;        "LDAP_OPT_CLIENT_CONTROLS" "GSLC_SSL_NO_AUTH"
885 ;        "GSLC_SSL_ONEWAY_AUTH" "GSLC_SSL_TWOWAY_AUTH" "MCAL_SUNDAY"
886 ;        "MCAL_MONDAY" "MCAL_TUESDAY" "MCAL_WEDNESDAY" "MCAL_THURSDAY"
887 ;        "MCAL_FRIDAY" "MCAL_SATURDAY" "MCAL_JANUARY" "MCAL_FEBRUARY"
888 ;        "MCAL_MARCH" "MCAL_APRIL" "MCAL_MAY" "MCAL_JUNE" "MCAL_JULY"
889 ;        "MCAL_AUGUST" "MCAL_SEPTEMBER" "MCAL_OCTOBER" "MCAL_NOVEMBER"
890 ;        "MCAL_RECUR_NONE" "MCAL_RECUR_DAILY" "MCAL_RECUR_WEEKLY"
891 ;        "MCAL_RECUR_MONTHLY_MDAY" "MCAL_RECUR_MONTHLY_WDAY"
892 ;        "MCAL_RECUR_YEARLY" "MCAL_M_SUNDAY" "MCAL_M_MONDAY"
893 ;        "MCAL_M_TUESDAY" "MCAL_M_WEDNESDAY" "MCAL_M_THURSDAY"
894 ;        "MCAL_M_FRIDAY" "MCAL_M_SATURDAY" "MCAL_M_WEEKDAYS"
895 ;        "MCAL_M_WEEKEND" "MCAL_M_ALLDAYS" "MCRYPT_" "MCRYPT_"
896 ;        "MCRYPT_ENCRYPT" "MCRYPT_DECRYPT" "MCRYPT_DEV_RANDOM"
897 ;        "MCRYPT_DEV_URANDOM" "MCRYPT_RAND" "SWFBUTTON_HIT"
898 ;        "SUNFUNCS_RET_STRING" "SUNFUNCS_RET_DOUBLE"
899 ;        "SWFBUTTON_DOWN" "SWFBUTTON_OVER" "SWFBUTTON_UP"
900 ;        "SWFBUTTON_MOUSEUPOUTSIDE" "SWFBUTTON_DRAGOVER"
901 ;        "SWFBUTTON_DRAGOUT" "SWFBUTTON_MOUSEUP" "SWFBUTTON_MOUSEDOWN"
902 ;        "SWFBUTTON_MOUSEOUT" "SWFBUTTON_MOUSEOVER"
903 ;        "SWFFILL_RADIAL_GRADIENT" "SWFFILL_LINEAR_GRADIENT"
904 ;        "SWFFILL_TILED_BITMAP" "SWFFILL_CLIPPED_BITMAP"
905 ;        "SWFTEXTFIELD_HASLENGTH" "SWFTEXTFIELD_NOEDIT"
906 ;        "SWFTEXTFIELD_PASSWORD" "SWFTEXTFIELD_MULTILINE"
907 ;        "SWFTEXTFIELD_WORDWRAP" "SWFTEXTFIELD_DRAWBOX"
908 ;        "SWFTEXTFIELD_NOSELECT" "SWFTEXTFIELD_HTML"
909 ;        "SWFTEXTFIELD_ALIGN_LEFT" "SWFTEXTFIELD_ALIGN_RIGHT"
910 ;        "SWFTEXTFIELD_ALIGN_CENTER" "SWFTEXTFIELD_ALIGN_JUSTIFY"
911 ;        "UDM_FIELD_URLID" "UDM_FIELD_URL" "UDM_FIELD_CONTENT"
912 ;        "UDM_FIELD_TITLE" "UDM_FIELD_KEYWORDS" "UDM_FIELD_DESC"
913 ;        "UDM_FIELD_DESCRIPTION" "UDM_FIELD_TEXT" "UDM_FIELD_SIZE"
914 ;        "UDM_FIELD_RATING" "UDM_FIELD_SCORE" "UDM_FIELD_MODIFIED"
915 ;        "UDM_FIELD_ORDER" "UDM_FIELD_CRC" "UDM_FIELD_CATEGORY"
916 ;        "UDM_PARAM_PAGE_SIZE" "UDM_PARAM_PAGE_NUM"
917 ;        "UDM_PARAM_SEARCH_MODE" "UDM_PARAM_CACHE_MODE"
918 ;        "UDM_PARAM_TRACK_MODE" "UDM_PARAM_PHRASE_MODE"
919 ;        "UDM_PARAM_CHARSET" "UDM_PARAM_STOPTABLE"
920 ;        "UDM_PARAM_STOP_TABLE" "UDM_PARAM_STOPFILE"
921 ;        "UDM_PARAM_STOP_FILE" "UDM_PARAM_WEIGHT_FACTOR"
922 ;        "UDM_PARAM_WORD_MATCH" "UDM_PARAM_MAX_WORD_LEN"
923 ;        "UDM_PARAM_MAX_WORDLEN" "UDM_PARAM_MIN_WORD_LEN"
924 ;        "UDM_PARAM_MIN_WORDLEN" "UDM_PARAM_ISPELL_PREFIXES"
925 ;        "UDM_PARAM_ISPELL_PREFIX" "UDM_PARAM_PREFIXES"
926 ;        "UDM_PARAM_PREFIX" "UDM_PARAM_CROSS_WORDS"
927 ;        "UDM_PARAM_CROSSWORDS" "UDM_LIMIT_CAT" "UDM_LIMIT_URL"
928 ;        "UDM_LIMIT_TAG" "UDM_LIMIT_LANG" "UDM_LIMIT_DATE"
929 ;        "UDM_PARAM_FOUND" "UDM_PARAM_NUM_ROWS" "UDM_PARAM_WORDINFO"
930 ;        "UDM_PARAM_WORD_INFO" "UDM_PARAM_SEARCHTIME"
931 ;        "UDM_PARAM_SEARCH_TIME" "UDM_PARAM_FIRST_DOC"
932 ;        "UDM_PARAM_LAST_DOC" "UDM_MODE_ALL" "UDM_MODE_ANY"
933 ;        "UDM_MODE_BOOL" "UDM_MODE_PHRASE" "UDM_CACHE_ENABLED"
934 ;        "UDM_CACHE_DISABLED" "UDM_TRACK_ENABLED" "UDM_TRACK_DISABLED"
935 ;        "UDM_PHRASE_ENABLED" "UDM_PHRASE_DISABLED"
936 ;        "UDM_CROSS_WORDS_ENABLED" "UDM_CROSSWORDS_ENABLED"
937 ;        "UDM_CROSS_WORDS_DISABLED" "UDM_CROSSWORDS_DISABLED"
938 ;        "UDM_PREFIXES_ENABLED" "UDM_PREFIX_ENABLED"
939 ;        "UDM_ISPELL_PREFIXES_ENABLED" "UDM_ISPELL_PREFIX_ENABLED"
940 ;        "UDM_PREFIXES_DISABLED" "UDM_PREFIX_DISABLED"
941 ;        "UDM_ISPELL_PREFIXES_DISABLED" "UDM_ISPELL_PREFIX_DISABLED"
942 ;        "UDM_ISPELL_TYPE_AFFIX" "UDM_ISPELL_TYPE_SPELL"
943 ;        "UDM_ISPELL_TYPE_DB" "UDM_ISPELL_TYPE_SERVER" "UDM_MATCH_WORD"
944 ;        "UDM_MATCH_BEGIN" "UDM_MATCH_SUBSTR" "UDM_MATCH_END"
945 ;        "MSQL_ASSOC" "MSQL_NUM" "MSQL_BOTH" "MYSQL_ASSOC" "MYSQL_NUM"
946 ;        "MYSQL_BOTH" "MYSQL_USE_RESULT" "MYSQL_STORE_RESULT"
947 ;        "OCI_DEFAULT" "OCI_DESCRIBE_ONLY" "OCI_COMMIT_ON_SUCCESS"
948 ;        "OCI_EXACT_FETCH" "SQLT_BFILEE" "SQLT_CFILEE" "SQLT_CLOB"
949 ;        "SQLT_BLOB" "SQLT_RDD" "OCI_B_SQLT_NTY" "OCI_SYSDATE"
950 ;        "OCI_B_BFILE" "OCI_B_CFILEE" "OCI_B_CLOB" "OCI_B_BLOB"
951 ;        "OCI_B_ROWID" "OCI_B_CURSOR" "OCI_B_BIN" "OCI_ASSOC" "OCI_NUM"
952 ;        "OCI_BOTH" "OCI_RETURN_NULLS" "OCI_RETURN_LOBS"
953 ;        "OCI_DTYPE_FILE" "OCI_DTYPE_LOB" "OCI_DTYPE_ROWID" "OCI_D_FILE"
954 ;        "OCI_D_LOB" "OCI_D_ROWID" "ODBC_TYPE" "ODBC_BINMODE_PASSTHRU"
955 ;        "ODBC_BINMODE_RETURN" "ODBC_BINMODE_CONVERT" "SQL_ODBC_CURSORS"
956 ;        "SQL_CUR_USE_DRIVER" "SQL_CUR_USE_IF_NEEDED" "SQL_CUR_USE_ODBC"
957 ;        "SQL_CONCURRENCY" "SQL_CONCUR_READ_ONLY" "SQL_CONCUR_LOCK"
958 ;        "SQL_CONCUR_ROWVER" "SQL_CONCUR_VALUES" "SQL_CURSOR_TYPE"
959 ;        "SQL_CURSOR_FORWARD_ONLY" "SQL_CURSOR_KEYSET_DRIVEN"
960 ;        "SQL_CURSOR_DYNAMIC" "SQL_CURSOR_STATIC" "SQL_KEYSET_SIZE"
961 ;        "SQL_CHAR" "SQL_VARCHAR" "SQL_LONGVARCHAR" "SQL_DECIMAL"
962 ;        "SQL_NUMERIC" "SQL_BIT" "SQL_TINYINT" "SQL_SMALLINT"
963 ;        "SQL_INTEGER" "SQL_BIGINT" "SQL_REAL" "SQL_FLOAT" "SQL_DOUBLE"
964 ;        "SQL_BINARY" "SQL_VARBINARY" "SQL_LONGVARBINARY" "SQL_DATE"
965 ;        "SQL_TIME" "SQL_TIMESTAMP" "SQL_TYPE_DATE" "SQL_TYPE_TIME"
966 ;        "SQL_TYPE_TIMESTAMP" "SQL_BEST_ROWID" "SQL_ROWVER"
967 ;        "SQL_SCOPE_CURROW" "SQL_SCOPE_TRANSACTION" "SQL_SCOPE_SESSION"
968 ;        "SQL_NO_NULLS" "SQL_NULLABLE" "SQL_INDEX_UNIQUE"
969 ;        "SQL_INDEX_ALL" "SQL_ENSURE" "SQL_QUICK"
970 ;        "X509_PURPOSE_SSL_CLIENT" "X509_PURPOSE_SSL_SERVER"
971 ;        "X509_PURPOSE_NS_SSL_SERVER" "X509_PURPOSE_SMIME_SIGN"
972 ;        "X509_PURPOSE_SMIME_ENCRYPT" "X509_PURPOSE_CRL_SIGN"
973 ;        "X509_PURPOSE_ANY" "PKCS7_DETACHED" "PKCS7_TEXT"
974 ;        "PKCS7_NOINTERN" "PKCS7_NOVERIFY" "PKCS7_NOCHAIN"
975 ;        "PKCS7_NOCERTS" "PKCS7_NOATTR" "PKCS7_BINARY" "PKCS7_NOSIGS"
976 ;        "OPENSSL_PKCS1_PADDING" "OPENSSL_SSLV23_PADDING"
977 ;        "OPENSSL_NO_PADDING" "OPENSSL_PKCS1_OAEP_PADDING"
978 ;        "ORA_BIND_INOUT" "ORA_BIND_IN" "ORA_BIND_OUT"
979 ;        "ORA_FETCHINTO_ASSOC" "ORA_FETCHINTO_NULLS"
980 ;        "PREG_PATTERN_ORDER" "PREG_SET_ORDER" "PREG_SPLIT_NO_EMPTY"
981 ;        "PREG_SPLIT_DELIM_CAPTURE"
982 ;        "PGSQL_ASSOC" "PGSQL_NUM" "PGSQL_BOTH"
983 ;        "PRINTER_COPIES" "PRINTER_MODE" "PRINTER_TITLE"
984 ;        "PRINTER_DEVICENAME" "PRINTER_DRIVERVERSION"
985 ;        "PRINTER_RESOLUTION_Y" "PRINTER_RESOLUTION_X" "PRINTER_SCALE"
986 ;        "PRINTER_BACKGROUND_COLOR" "PRINTER_PAPER_LENGTH"
987 ;        "PRINTER_PAPER_WIDTH" "PRINTER_PAPER_FORMAT"
988 ;        "PRINTER_FORMAT_CUSTOM" "PRINTER_FORMAT_LETTER"
989 ;        "PRINTER_FORMAT_LEGAL" "PRINTER_FORMAT_A3" "PRINTER_FORMAT_A4"
990 ;        "PRINTER_FORMAT_A5" "PRINTER_FORMAT_B4" "PRINTER_FORMAT_B5"
991 ;        "PRINTER_FORMAT_FOLIO" "PRINTER_ORIENTATION"
992 ;        "PRINTER_ORIENTATION_PORTRAIT" "PRINTER_ORIENTATION_LANDSCAPE"
993 ;        "PRINTER_TEXT_COLOR" "PRINTER_TEXT_ALIGN" "PRINTER_TA_BASELINE"
994 ;        "PRINTER_TA_BOTTOM" "PRINTER_TA_TOP" "PRINTER_TA_CENTER"
995 ;        "PRINTER_TA_LEFT" "PRINTER_TA_RIGHT" "PRINTER_PEN_SOLID"
996 ;        "PRINTER_PEN_DASH" "PRINTER_PEN_DOT" "PRINTER_PEN_DASHDOT"
997 ;        "PRINTER_PEN_DASHDOTDOT" "PRINTER_PEN_INVISIBLE"
998 ;        "PRINTER_BRUSH_SOLID" "PRINTER_BRUSH_CUSTOM"
999 ;        "PRINTER_BRUSH_DIAGONAL" "PRINTER_BRUSH_CROSS"
1000 ;        "PRINTER_BRUSH_DIAGCROSS" "PRINTER_BRUSH_FDIAGONAL"
1001 ;        "PRINTER_BRUSH_HORIZONTAL" "PRINTER_BRUSH_VERTICAL"
1002 ;        "PRINTER_FW_THIN" "PRINTER_FW_ULTRALIGHT" "PRINTER_FW_LIGHT"
1003 ;        "PRINTER_FW_NORMAL" "PRINTER_FW_MEDIUM" "PRINTER_FW_BOLD"
1004 ;        "PRINTER_FW_ULTRABOLD" "PRINTER_FW_HEAVY" "PRINTER_ENUM_LOCAL"
1005 ;        "PRINTER_ENUM_NAME" "PRINTER_ENUM_SHARED"
1006 ;        "PRINTER_ENUM_DEFAULT" "PRINTER_ENUM_CONNECTIONS"
1007 ;        "PRINTER_ENUM_NETWORK" "PRINTER_ENUM_REMOTE" "PSPELL_FAST"
1008 ;        "PSPELL_NORMAL" "PSPELL_BAD_SPELLERS" "PSPELL_RUN_TOGETHER"
1009 ;        "SID" "SID" "AF_UNIX" "AF_INET" "SOCK_STREAM" "SOCK_DGRAM"
1010 ;        "SOCK_RAW" "SOCK_SEQPACKET" "SOCK_RDM" "MSG_OOB" "MSG_WAITALL"
1011 ;        "MSG_PEEK" "MSG_DONTROUTE" "SO_DEBUG" "SO_REUSEADDR"
1012 ;        "SO_KEEPALIVE" "SO_DONTROUTE" "SO_LINGER" "SO_BROADCAST"
1013 ;        "SO_OOBINLINE" "SO_SNDBUF" "SO_RCVBUF" "SO_SNDLOWAT"
1014 ;        "SO_RCVLOWAT" "SO_SNDTIMEO" "SO_RCVTIMEO" "SO_TYPE" "SO_ERROR"
1015 ;        "SOL_SOCKET" "PHP_NORMAL_READ" "PHP_BINARY_READ"
1016 ;        "PHP_SYSTEM_READ" "SOL_TCP" "SOL_UDP" "MOD_COLOR" "MOD_MATRIX"
1017 ;        "TYPE_PUSHBUTTON" "TYPE_MENUBUTTON" "BSHitTest" "BSDown"
1018 ;        "BSOver" "BSUp" "OverDowntoIdle" "IdletoOverDown"
1019 ;        "OutDowntoIdle" "OutDowntoOverDown" "OverDowntoOutDown"
1020 ;        "OverUptoOverDown" "OverUptoIdle" "IdletoOverUp" "ButtonEnter"
1021 ;        "ButtonExit" "MenuEnter" "MenuExit" "XML_ERROR_NONE"
1022 ;        "XML_ERROR_NO_MEMORY" "XML_ERROR_SYNTAX"
1023 ;        "XML_ERROR_NO_ELEMENTS" "XML_ERROR_INVALID_TOKEN"
1024 ;        "XML_ERROR_UNCLOSED_TOKEN" "XML_ERROR_PARTIAL_CHAR"
1025 ;        "XML_ERROR_TAG_MISMATCH" "XML_ERROR_DUPLICATE_ATTRIBUTE"
1026 ;        "XML_ERROR_JUNK_AFTER_DOC_ELEMENT" "XML_ERROR_PARAM_ENTITY_REF"
1027 ;        "XML_ERROR_UNDEFINED_ENTITY" "XML_ERROR_RECURSIVE_ENTITY_REF"
1028 ;        "XML_ERROR_ASYNC_ENTITY" "XML_ERROR_BAD_CHAR_REF"
1029 ;        "XML_ERROR_BINARY_ENTITY_REF"
1030 ;        "XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF"
1031 ;        "XML_ERROR_MISPLACED_XML_PI" "XML_ERROR_UNKNOWN_ENCODING"
1032 ;        "XML_ERROR_INCORRECT_ENCODING"
1033 ;        "XML_ERROR_UNCLOSED_CDATA_SECTION"
1034 ;        "XML_ERROR_EXTERNAL_ENTITY_HANDLING" "XML_OPTION_CASE_FOLDING"
1035 ;        "XML_OPTION_TARGET_ENCODING" "XML_OPTION_SKIP_TAGSTART"
1036 ;        "XML_OPTION_SKIP_WHITE" "YPERR_BADARGS" "YPERR_BADDB"
1037 ;        "YPERR_BUSY" "YPERR_DOMAIN" "YPERR_KEY" "YPERR_MAP"
1038 ;        "YPERR_NODOM" "YPERR_NOMORE" "YPERR_PMAP" "YPERR_RESRC"
1039 ;        "YPERR_RPC" "YPERR_YPBIND" "YPERR_YPERR" "YPERR_YPSERV"
1040 ;        "YPERR_VERS" "FORCE_GZIP" "FORCE_DEFLATE"
1041
1042        ;; PEAR constants
1043 ;        "PEAR_ERROR_RETURN" "PEAR_ERROR_PRINT" "PEAR_ERROR_TRIGGER"
1044 ;        "PEAR_ERROR_DIE" "PEAR_ERROR_CALLBACK" "OS_WINDOWS" "OS_UNIX"
1045 ;        "PEAR_OS" "DB_OK" "DB_ERROR" "DB_ERROR_SYNTAX"
1046 ;        "DB_ERROR_CONSTRAINT" "DB_ERROR_NOT_FOUND"
1047 ;        "DB_ERROR_ALREADY_EXISTS" "DB_ERROR_UNSUPPORTED"
1048 ;        "DB_ERROR_MISMATCH" "DB_ERROR_INVALID" "DB_ERROR_NOT_CAPABLE"
1049 ;        "DB_ERROR_TRUNCATED" "DB_ERROR_INVALID_NUMBER"
1050 ;        "DB_ERROR_INVALID_DATE" "DB_ERROR_DIVZERO"
1051 ;        "DB_ERROR_NODBSELECTED" "DB_ERROR_CANNOT_CREATE"
1052 ;        "DB_ERROR_CANNOT_DELETE" "DB_ERROR_CANNOT_DROP"
1053 ;        "DB_ERROR_NOSUCHTABLE" "DB_ERROR_NOSUCHFIELD"
1054 ;        "DB_ERROR_NEED_MORE_DATA" "DB_ERROR_NOT_LOCKED"
1055 ;        "DB_ERROR_VALUE_COUNT_ON_ROW" "DB_ERROR_INVALID_DSN"
1056 ;        "DB_ERROR_CONNECT_FAILED" "DB_WARNING" "DB_WARNING_READ_ONLY"
1057 ;        "DB_PARAM_SCALAR" "DB_PARAM_OPAQUE" "DB_BINMODE_PASSTHRU"
1058 ;        "DB_BINMODE_RETURN" "DB_BINMODE_CONVERT" "DB_FETCHMODE_DEFAULT"
1059 ;        "DB_FETCHMODE_ORDERED" "DB_FETCHMODE_ASSOC"
1060 ;        "DB_FETCHMODE_FLIPPED" "DB_GETMODE_ORDERED" "DB_GETMODE_ASSOC"
1061 ;        "DB_GETMODE_FLIPPED" "DB_TABLEINFO_ORDER"
1062 ;        "DB_TABLEINFO_ORDERTABLE" "DB_TABLEINFO_FULL"
1063
1064        )))
1065   "PHP constants.")
1066
1067 (defconst php-keywords
1068   (eval-when-compile
1069     (regexp-opt
1070      ;; "class", "new" and "extends" get special treatment
1071      ;; "case" and  "default" get special treatment elsewhere
1072      '("and" "as" "break" "continue" "declare" "do" "echo" "else" "elseif"
1073        "endfor" "endforeach" "endif" "endswitch" "endwhile" "exit"
1074        "extends" "for" "foreach" "global" "if" "include" "include_once"
1075        "next" "or" "require" "require_once" "return" "static" "switch"
1076        "then" "var" "while" "xor" "throw" "catch" "try"
1077        "instanceof" "catch all" "finally")))
1078   "PHP keywords.")
1079
1080 (defconst php-identifier
1081   (eval-when-compile
1082     '"[a-zA-Z\_\x7f-\xff][a-zA-Z0-9\_\x7f-\xff]*")
1083   "Characters in a PHP identifier.")
1084
1085 (defconst php-types
1086   (eval-when-compile
1087     (regexp-opt '("array" "bool" "boolean" "char" "const" "double" "float"
1088                   "int" "integer" "long" "mixed" "object" "real"
1089                   "string")))
1090   "PHP types.")
1091
1092 (defconst php-superglobals
1093   (eval-when-compile
1094     (regexp-opt '("_GET" "_POST" "_COOKIE" "_SESSION" "_ENV" "GLOBALS"
1095                   "_SERVER" "_FILES" "_REQUEST")))
1096   "PHP superglobal variables.")
1097
1098 ;; Set up font locking
1099 (defconst php-font-lock-keywords-1
1100   (list
1101    ;; Fontify constants
1102    (cons
1103     (concat "[^_$]?\\<\\(" php-constants "\\)\\>[^_]?")
1104     '(1 font-lock-constant-face))
1105
1106    ;; Fontify keywords
1107    (cons
1108     (concat "[^_$]?\\<\\(" php-keywords "\\)\\>[^_]?")
1109     '(1 font-lock-keyword-face))
1110
1111    ;; Fontify keywords and targets, and case default tags.
1112    (list "\\<\\(break\\|case\\|continue\\)\\>\\s-+\\(-?\\sw+\\)?"
1113          '(1 font-lock-keyword-face) '(2 font-lock-constant-face t t))
1114    ;; This must come after the one for keywords and targets.
1115    '(":" ("^\\s-+\\(\\sw+\\)\\s-+\\s-+$"
1116           (beginning-of-line) (end-of-line)
1117           (1 font-lock-constant-face)))
1118
1119    ;; treat 'print' as keyword only when not used like a function name
1120    '("\\<print\\s-*(" . php-default-face)
1121    '("\\<print\\>" . font-lock-keyword-face)
1122
1123    ;; Fontify PHP tag
1124    (cons php-tags-key font-lock-preprocessor-face)
1125
1126    ;; Fontify ASP-style tag
1127    '("<\\%\\(=\\)?" . font-lock-preprocessor-face)
1128    '("\\%>" . font-lock-preprocessor-face)
1129
1130    )
1131   "Subdued level highlighting for PHP mode.")
1132
1133 (defconst php-font-lock-keywords-2
1134   (append
1135    php-font-lock-keywords-1
1136    (list
1137
1138     ;; class declaration
1139     '("\\<\\(class\\|interface\\)\\s-+\\(\\sw+\\)?"
1140       (1 font-lock-keyword-face) (2 font-lock-type-face nil t))
1141     ;; handle several words specially, to include following word,
1142     ;; thereby excluding it from unknown-symbol checks later
1143     ;; FIX to handle implementing multiple
1144     ;; currently breaks on "class Foo implements Bar, Baz"
1145     '("\\<\\(new\\|extends\\|implements\\)\\s-+\\$?\\(\\sw+\\)"
1146       (1 font-lock-keyword-face) (2 font-lock-type-face))
1147
1148     ;; function declaration
1149     '("\\<\\(function\\)\\s-+&?\\(\\sw+\\)\\s-*("
1150       (1 font-lock-keyword-face)
1151       (2 font-lock-function-name-face nil t))
1152
1153     ;; class hierarchy
1154     '("\\<\\(self\\|parent\\)\\>" (1 font-lock-constant-face nil nil))
1155
1156     ;; method and variable features
1157     '("\\<\\(private\\|protected\\|public\\)\\s-+\\$?\\sw+"
1158       (1 font-lock-keyword-face))
1159
1160     ;; method features
1161     '("^\\s-*\\(abstract\\|static\\|final\\)\\s-+\\$?\\sw+"
1162       (1 font-lock-keyword-face))
1163
1164     ;; variable features
1165     '("^\\s-*\\(static\\|const\\)\\s-+\\$?\\sw+"
1166       (1 font-lock-keyword-face))
1167     ))
1168   "Medium level highlighting for PHP mode.")
1169
1170 (defconst php-font-lock-keywords-3
1171   (append
1172    php-font-lock-keywords-2
1173    (list
1174
1175     ;; <word> or </word> for HTML
1176     ;;'("</?\\sw+[^> ]*>" . font-lock-constant-face)
1177     ;;'("</?\\sw+[^>]*" . font-lock-constant-face)
1178     ;;'("<!DOCTYPE" . font-lock-constant-face)
1179     '("</?[a-z!:]+" . font-lock-constant-face)
1180
1181     ;; HTML >
1182     '("<[^>]*\\(>\\)" (1 font-lock-constant-face))
1183
1184     ;; HTML tags
1185     '("\\(<[a-z]+\\)[[:space:]]+\\([a-z:]+=\\)[^>]*?" (1 font-lock-constant-face) (2 font-lock-constant-face) )
1186     '("\"[[:space:]]+\\([a-z:]+=\\)" (1 font-lock-constant-face))
1187
1188     ;; HTML entities
1189     ;;'("&\\w+;" . font-lock-variable-name-face)
1190
1191     ;; warn about '$' immediately after ->
1192     '("\\$\\sw+->\\s-*\\(\\$\\)\\(\\sw+\\)"
1193       (1 font-lock-warning-face) (2 php-default-face))
1194
1195     ;; warn about $word.word -- it could be a valid concatenation,
1196     ;; but without any spaces we'll assume $word->word was meant.
1197     '("\\$\\sw+\\(\\.\\)\\sw"
1198       1 font-lock-warning-face)
1199
1200     ;; Warn about ==> instead of =>
1201     '("==+>" . font-lock-warning-face)
1202
1203     ;; exclude casts from bare-word treatment (may contain spaces)
1204     `(,(concat "(\\s-*\\(" php-types "\\)\\s-*)")
1205       1 font-lock-type-face)
1206
1207     ;; PHP5: function declarations may contain classes as parameters type
1208     `(,(concat "[(,]\\s-*\\(\\sw+\\)\\s-+&?\\$\\sw+\\>")
1209       1 font-lock-type-face)
1210
1211     ;; Fontify variables and function calls
1212     '("\\$\\(this\\|that\\)\\W" (1 font-lock-constant-face nil nil))
1213     `(,(concat "\\$\\(" php-superglobals "\\)\\W")
1214       (1 font-lock-constant-face nil nil)) ;; $_GET & co
1215     '("\\$\\(\\sw+\\)" (1 font-lock-variable-name-face)) ;; $variable
1216     '("->\\(\\sw+\\)" (1 font-lock-variable-name-face t t)) ;; ->variable
1217     '("->\\(\\sw+\\)\\s-*(" . (1 php-default-face t t)) ;; ->function_call
1218     '("\\(\\sw+\\)::\\sw+\\s-*(?" . (1 font-lock-type-face)) ;; class::member
1219     '("::\\(\\sw+\\>[^(]\\)" . (1 php-default-face)) ;; class::constant
1220     '("\\<\\sw+\\s-*[[(]" . php-default-face) ;; word( or word[
1221     '("\\<[0-9]+" . php-default-face) ;; number (also matches word)
1222
1223     ;; Warn on any words not already fontified
1224     '("\\<\\sw+\\>" . font-lock-warning-face)
1225
1226     ))
1227   "Gauchy level highlighting for PHP mode.")
1228
1229 (provide 'php-mode)
1230
1231 ;;; php-mode.el ends here