Pragmatism in the real world

Recursive PHP lint

There are many scripts that recursively execute php -l on a set of files or directories. This is mine:

#!/usr/bin/env bash
set -o nounset

# Recursively call `php -l` over the specified directories/files

if [ -z "$1" ] ; then
    printf 'Usage: %s  ...\n' "$(basename "$0")"
    exit 1
fi

ERROR=false
SAVEIFS=$IFS
IFS=$'\n'
while test $# -gt 0; do
    CURRENT=${1%/}
    shift

    if [ ! -f $CURRENT ] && [ ! -d $CURRENT ] ; then
        echo "$CURRENT cannot be found"
        ERROR=true
        continue
    fi

    for FILE in $(find $CURRENT -type f -name "*.php") ; do
        OUTPUT=$(php -l "$FILE" 2> /dev/null)

        # Remove blank lines from the `php -l` output
        OUTPUT=$(echo -e "$OUTPUT" | awk 'NF')

        if [ "$OUTPUT" != "No syntax errors detected in $FILE" ] ; then
            echo -e "$FILE:"
            echo -e "  ${OUTPUT//$'\n'/\\n  }\n"
            ERROR=true
        fi
    done
done

IFS=$SAVEIFS

if [ "$ERROR" = true ] ; then
    exit 1
fi

echo "No syntax errors found."
exit 0

I store it in ~/bin and usually run it like this:

$ cd project
$ phplint .
No syntax errors found.

There are a few interesting bash tricks that I picked up when I wrote this.

Firstly, you need to set IFS to break on new line rather than space otherwise the find command doesn’t work with spaces in file names.

I also discovered that the output of php -l has quite a lot of blank lines in its output that I didn’t want. OUTPUT=$(echo -e "$OUTPUT" | awk 'NF') solves this nicely.

I also wanted to indent the output and used bash’s parameter expansion system to replace a new line with a new line and two spaces using ${OUTPUT//$'\n'/\\n }

Maybe you’ll find this useful or it’ll work as the basis for a script you need to write.

2 thoughts on “Recursive PHP lint

  1. This is mine:

    #!/usr/bin/env bash
    
    PHP_EXECUTABLE=${1:-php}
    found_lint_errors=0
    errors_list=""
    
    #find all the .php files in the current directory, exclude the vendor directory.
    while IFS= read -r -d '' file; do
        OUT=$($PHP_EXECUTABLE -lf "$file" 2> /tmp/errFile)
        ERR=$(</tmp/errFile)
        if [ "$OUT" != "No syntax errors detected in $file" ]; then
            errors_list="$errors_list $OUT \n"
            found_lint_errors=1
            printf "E"
        elif [[ ! -z $ERR  ]]; then
            errors_list="$errors_list $ERR \n"
            found_lint_errors=1 # Uncomment to turn warnings to errors
            printf "W"
        else
        printf '.'
        fi
    done < <(find . -path ./vendor -prune -o -type f -name '*.php' -print0)
    
    if [ $found_lint_errors -eq 1 ]; then
        printf "\n"
        printf "✗ Syntax errors encountered: \n$errors_list \nExiting with code 1\n"
        exit 1
    fi
    
    exit 0
    

Comments are closed.