Checking Syntax Errors In PHP And JavaScript Using Phing

29th October 2012

Checking Syntax Errors In PHP And JavaScript Using Phing

Running a simple syntax check over your files is a good way to save time. This can be when testing code but best practice is to not to even commit code that contains syntax errors.

You can syntax check a single file using the -l (lowercase L) flag with the PHP executable like this.

$ php -l file.php

Unfortunately this can only check one file at a time so I set about trying to find a good way of checking a whole project at once. There are a couple of scripts available on the internet, but I set about creating my own solution using the phplint task in Phing. This means that I can just create a fileset and feed this into the phplint task without having to rewrite the whole thing if I wanted to include (or exclude) a particular directory or file.

I work with Drupal a lot so I wanted to run a quick syntax check on a Drupal project to see if there was anything wrong with it. This meant setting up the following fileset, which includes the code php files in the root as well as the PHP files with the extensions .php, .inc and .module that are usually found in a Drupal project.

  1. <fileset dir="." id="phpfiles">
  2. <include name="*.php" />
  3. <include name="**/*.php" />
  4. <include name="**/*.inc" />
  5. <include name="**/*.module" />
  6. </fileset>

The next step was to create the phplint target so that I could run the phplint task over the fileset. This is quite simple to do.

  1. <target name="main">
  2. <phplint>
  3. <fileset refid="phpfiles" />
  4. </phplint>
  5. </target>

Saving this build script as build.xml means you can check an entire project just by running it over the directory you are currently in. You can do this using the -f flag to include the needed build.xml file you want.

phing -f /path/to/buildfile/build.xml

As a test I ran it over a Drupal project I was currently working on. It turned out that it did contain a syntax error, although it was in third party code. Here is the error, which was in the Date module:

[phplint] Parse error: syntax error, unexpected '*' in ./docroot/sites/all/modules/contrib/date/api.date.php on line 166

After a quick look at the source code I found the offending line of code. Notice the extra closing comment block. This file wasn't part of the running code, it was used to generate API documentation, but the phplint task was still able to pick it out.

  1. /**
  2.  * This hook lets other modules alter the local date objects created by the date_combo validation
  3.  * before they are converted back to the database timezone and stored.
  4.  *
  5.  * @param $date - the $date object.
  6.  * @param $fom_state - the $form_state array.
  7.  * @param $context, and array containing:
  8.  * 'field' - the $field array.
  9.  * 'instance' - the $instance array.
  10.  * 'item' - the $item array.
  11.  * 'element' - the $element array.
  12.  */
  13. */
  14. function date_all_day_date_combo_validate_date_end_alter(&$date, &$form_state, $context) {
  15.  
  16. // If this is an 'All day' value, set the time to midnight.
  17. if (!empty($context['element']['#date_is_all_day'])) {
  18. $date->setTime(0, 0, 0);
  19. }
  20. }

Checking JavaScript for syntax errors is slightly more tricky, but is very possible using the JavaScript lint program and the jsllint phing task. To get this working you will need to download the JavaScript lint file from http://www.javascriptlint.com/download.htm and compile it using the following commands (on a Linux system). The following commands compile jslint and then copy the executable file to a place that can be seen by the operating system.

  1. $ make -f Makefile.ref
  2. $ sudo cp Linux_All_DBG.OBJ/jsl /usr/local/bin/jsl

Once done, you can check that it's installed by running "jsl" on it's own. To set up the jsllint task you need to have some JavaScript files, which the following fileset will take care of.

  1. <fileset dir="." id="jsfiles">
  2. <include name="*.js" />
  3. <include name="**/*.js" />
  4. </fileset>

Now all we need to do is feed this fileset into jsllint target that just runs the jsllint task. Take care to add two l's here to the task name here.

  1. <target name="jsllint">
  2. <jsllint showwarnings="false">
  3. <fileset refid="jsfiles" />
  4. </jsllint>
  5. </target>

You might notice that I have set the showwarnings setting to false. This is because when I first ran it on the Drupal project I was working on I had literally hundreds of warnings. Turning off warnings stops this massive amount of output so you can concentrate on the errors. When I did this on my project I had no syntax errors.

It is possible syntax check XML using the xmllint phing task, although this requires the use of a schema to check the XML against and so bulk checking a project isn't possible. You would need a schema file for every XML file type you found, which generally doesn't exist.

Putting the phplint and the jsllint parts together we end up with a Phing build file that looks like the following. Plugging this file into Phing will syntax check all of the PHP and JavaScript files in a project, although this is specifically set up to inspect a Drupal project.

  1. <?xml version="1.0"?>
  2. <project name="lint" default="main">
  3. <fileset dir="." id="phpfiles">
  4. <include name="*.php" />
  5. <include name="**/*.php" />
  6. <include name="**/*.inc" />
  7. <include name="**/*.module" />
  8. </fileset>
  9.  
  10. <fileset dir="." id="jsfiles">
  11. <include name="*.js" />
  12. <include name="**/*.js" />
  13. </fileset>
  14.  
  15. <target name="main">
  16. <phingcall target="phplint" />
  17. <phingcall target="jslint" />
  18. </target>
  19.  
  20. <target name="phplint">
  21. <phplint>
  22. <fileset refid="phpfiles" />
  23. </phplint>
  24. </target>
  25.  
  26. <target name="jslint">
  27. <jsllint showwarnings="false">
  28. <fileset refid="jsfiles" />
  29. </jsllint>
  30. </target>
  31.  
  32. </project>

Here are the relevant Phing documentation pages:

Add new comment

The content of this field is kept private and will not be shown publicly.