AVNLIPPP -- Average variable name length in popular PHP projects
#!/usr/bin/env bash
set -o errexit # Exit script when a command exits with non-zero status.
set -o errtrace # Exit on error inside any functions or sub-shells.
set -o nounset # Exit script on use of an undefined variable.
set -o pipefail # Return exit status of the last command in the pipe that exited with a non-zero exit code
: readonly "${GRAPH_URL:=https://image-charts.com/chart?chs=800x600&cht=bvs&chds=a&chxt=x,y&chg=1,1&chco=777BB3&chtt=%s+PHP+variable+name+length&chd=t:0,%s}"
# : readonly "${NORMAL_OUTPUT:=/dev/stdout}"
: readonly "${NORMAL_OUTPUT:=/dev/null}"
: readonly "${WORKING_DIRECTORY:=$PWD}"
: readonly "${ACK:=ack-grep}"
variable-names-length-per-php-project() {
calculate-average() {
local -a aScoreList
local -i iAverage=0 iCount iIndex iTotal=0 iTotalCount=0
local sScoreList
readonly sScoreList="${1?One parameter required: <score-list>}"
readonly aScoreList=( ${sScoreList//,/ } )
for iIndex in "${!aScoreList[@]}"; do
iCount="${aScoreList[${iIndex}]}"
if [[ "${iCount}" -ne 0 ]];then
iTotal=$(( iTotal + $((iCount * $((iIndex+1))))))
fi
iTotalCount=$(( iTotalCount + iCount ))
done
if [[ ${iTotalCount} -gt 0 ]];then
iAverage=$(( iTotal / iTotalCount ));
fi
echo "${iAverage}"
}
calculate-minimum() {
local -a aScoreList
local -i iIndex iMinimum=0
local sScoreList
readonly sScoreList="${1?One parameter required: <score-list>}"
readonly aScoreList=( ${sScoreList//,/ } )
for iIndex in "${!aScoreList[@]}"; do
if [[ "${aScoreList[${iIndex}]}" -ne 0 ]];then
readonly iMinimum=$((iIndex + 1))
break
fi
done
echo "${iMinimum}";
}
calculate-maximum() {
local -a aScoreList
local -i iIndex iMaximum=0
local sScoreList
readonly sScoreList="${1?One parameter required: <score-list>}"
readonly aScoreList=( ${sScoreList//,/ } )
for iIndex in "${!aScoreList[@]}"; do
if [[ "${aScoreList[${iIndex}]}" -ne 0 ]];then
iMaximum=$((iIndex + 1))
fi
done
echo "${iMaximum}";
}
clear-line() {
tput cuu 1 && tput el
}
create-variables-list() {
local -i iCounter iResult
local sDirectory sPattern sResult=''
readonly sDirectory="${1?One parameter required: <directory-to-scan>}"
for iCounter in {1..50};do
sPattern='\$[a-zA-Z0-9_]{'${iCounter}'}\b';
iResult="$(create-ack-list "${sPattern}" "${sDirectory}" | wc -l)"
sResult+="${iResult},"
done
# Remove trailing comma
echo "${sResult:0:-1}"
}
create-ack-list() {
local sDirectory sPattern
readonly sPattern="${1?Two parameters required: <ack-pattern> <directory-to-scan>}"
readonly sDirectory="${2?Two parameters required: <ack-pattern> <directory-to-scan>}"
{ "${ACK}" \
--php \
--ignore-file='match:/^.*(\.phar|Test.php)$/' \
--match "${sPattern}" \
-o \
--ignore-dir=vendor --ignore-dir=var \
"${sDirectory}" \
| cut -d ':' -f 3 \
| sort -u
} || echo -n ''
}
fetch-github-list() {
curl -s 'https://api.github.com/search/repositories?q=language%3APHP&sort=stars&language=php' \
| grep 'clone_url' \
| cut -d'"' -f4
}
print-topic() {
echo -e " =====> $*\n" >> "${NORMAL_OUTPUT}"
}
print-status() {
echo -e " -----> $*\n" >> "${NORMAL_OUTPUT}"
}
main() {
local -a aProjects
local sDetailResult sDirectory sFile sImagesUrl sProject sResult sSummaryResult sUrl
mkdir -p "${WORKING_DIRECTORY}/build/"
if [[ ! -f "${WORKING_DIRECTORY}/github.log" ]];then
print-topic 'Fetching project list from Github'
echo "$(fetch-github-list)" > "${WORKING_DIRECTORY}/github.log"
fi
readonly aProjects=( $(cat "${WORKING_DIRECTORY}/github.log" ) )
for sUrl in "${aProjects[@]}";do
print-topic 'Processing project list'
sProject="$(echo "${sUrl:19:-4}" | tr '/' '_')"
sDirectory="${WORKING_DIRECTORY}/${sProject}"
if [[ "${sProject}" = '' ]];then
echo " ! ERROR"
exit 90
fi
if [[ ! -f "${WORKING_DIRECTORY}/build/${sProject}.txt" ]];then
if [[ ! -d "${WORKING_DIRECTORY}/${sProject}" ]];then
print-status "Cloning ${sUrl}"
git clone ${sUrl} "${WORKING_DIRECTORY}/${sProject}"
fi
print-status "Creating list of variables for ${sProject}"
echo "$(create-variables-list "${sDirectory}")" > "${WORKING_DIRECTORY}/build/${sProject}.txt"
if [[ -d "${WORKING_DIRECTORY}/${sProject}" ]];then
rm -rdf "${WORKING_DIRECTORY}/${sProject}"
fi
fi
done
sSummaryResult=''
sDetailResult=''
for sFile in "${WORKING_DIRECTORY}/build/"*".txt";do
sProject="$(basename ${sFile:0:-4} | tr '_' '/')"
sResult="$(cat ${sFile})"
iAverage=$(calculate-average "${sResult}")
iMin=$(calculate-minimum "${sResult}")
iMax=$(calculate-maximum "${sResult}")
sImagesUrl="$(printf "${GRAPH_URL}" "${sProject}" "${sResult}")"
# sSummaryResult+="$(printf '%2i (min:%2i | max:%2i) %s' "${iAverage}" "${iMin}" "${iMax}" "${sProject}")\n"
sSummaryResult+="$(printf '| %2i | %2i | %2i | [%s](https://github.com/%s) |' "${iAverage}" "${iMin}" "${iMax}" "${sProject}" "${sProject}")\n"
# if [[ ! -f "${WORKING_DIRECTORY}/build/${sProject}.png" ]];then
# print-status "Downloading graph image for ${sProject}"
# wget --quiet --output-document="${WORKING_DIRECTORY}/${sProject}.png" "${sImagesUrl}"
# fi
sDetailResult+="$(
printf '\n\n### %s\n\n![](%s)\n\n- Average: %2i\n- Shortest: %2i\n- Longest: %2i\n' \
"${sProject}" "${sImagesUrl}" "${iAverage}" "${iMin}" "${iMax}"
)"
done
# echo -e "${sSummaryResult}" | sort -bdf -k1,1nr -k5,5
echo '| Average | Shortest | Longest | Project |'
echo '| --- | --- | --- | ---|'
echo -e "${sSummaryResult}" | sort -t'|' -bdf -k2,2nr -k6,6nr
echo -e "${sDetailResult}"
}
main "${@}"
}
if [[ ${BASH_SOURCE[0]} != $0 ]]; then
export -f variable-names-length-per-php-project
else
variable-names-length-per-php-project "${@}"
exit ${?}
fi
# EOF
Average variable name length in popular PHP projects
This project show the average length of variable names of the Top 30 (by ammount of stars) PHP projects on Github.
The logic that is used to retrieve these values has been included as a separate shell script.
Average | Shortest | Longest | Project |
---|---|---|---|
12 | 1 | 48 | matomo-org/matomo |
11 | 1 | 49 | WordPress/WordPress |
10 | 1 | 27 | octobercms/october |
10 | 1 | 29 | composer/composer |
10 | 1 | 35 | phacility/phabricator |
10 | 1 | 39 | yiisoft/yii2 |
10 | 1 | 41 | symfony/symfony |
10 | 1 | 47 | sebastianbergmann/phpunit |
9 | 1 | 29 | CachetHQ/Cachet |
9 | 1 | 32 | PHPOffice/PHPExcel |
9 | 1 | 36 | fzaninotto/Faker |
9 | 1 | 38 | getgrav/grav |
8 | 1 | 23 | bcit-ci/CodeIgniter |
8 | 1 | 23 | slimphp/Slim |
8 | 1 | 26 | Seldaek/monolog |
8 | 1 | 26 | dingo/api |
8 | 1 | 34 | cakephp/cakephp |
8 | 1 | 36 | laravel/framework |
8 | 3 | 19 | serbanghita/Mobile-Detect |
7 | 1 | 15 | domnikl/DesignPatternsPHP |
7 | 1 | 23 | barryvdh/laravel-debugbar |
7 | 1 | 23 | guzzle/guzzle |
7 | 1 | 23 | phalcon/cphalcon |
7 | 1 | 26 | phanan/koel |
7 | 1 | 28 | PHPMailer/PHPMailer |
6 | 1 | 17 | briannesbitt/Carbon |
6 | 1 | 17 | roots/sage |
6 | 2 | 16 | laravel/laravel |
5 | 1 | 20 | danielmiessler/SecLists |
0 | 0 | 0 | flarum/flarum |