{"id":33234395,"url":"https://edgedesigncz.github.io/phpqa/","last_synced_at":"2025-11-21T12:02:14.420Z","repository":{"id":32822431,"uuid":"36415342","full_name":"EdgedesignCZ/phpqa","owner":"EdgedesignCZ","description":"Analyze PHP code with one command","archived":false,"fork":false,"pushed_at":"2025-11-21T07:11:40.000Z","size":2778,"stargazers_count":561,"open_issues_count":0,"forks_count":58,"subscribers_count":17,"default_branch":"master","last_synced_at":"2025-11-21T08:35:49.464Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://edgedesigncz.github.io/phpqa","language":"XSLT","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/EdgedesignCZ.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2015-05-28T04:46:59.000Z","updated_at":"2025-11-21T07:07:13.000Z","dependencies_parsed_at":"2024-01-03T02:23:03.266Z","dependency_job_id":"2b1a4fd9-de1d-4ce5-9b7a-7851f423b846","html_url":"https://github.com/EdgedesignCZ/phpqa","commit_stats":{"total_commits":589,"total_committers":18,"mean_commits":32.72222222222222,"dds":0.05772495755517826,"last_synced_commit":"a3038f1e488fd11d660c47b2fd71cad2773e23b3"},"previous_names":[],"tags_count":49,"template":false,"template_full_name":null,"purl":"pkg:github/EdgedesignCZ/phpqa","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EdgedesignCZ%2Fphpqa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EdgedesignCZ%2Fphpqa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EdgedesignCZ%2Fphpqa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EdgedesignCZ%2Fphpqa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EdgedesignCZ","download_url":"https://codeload.github.com/EdgedesignCZ/phpqa/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EdgedesignCZ%2Fphpqa/sbom","scorecard":{"id":44332,"data":{"date":"2025-08-11","repo":{"name":"github.com/EdgedesignCZ/phpqa","commit":"9737b48a7a4befdf24722ad111280712c3846075"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":5.3,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":10,"reason":"17 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":2,"reason":"Found 3/14 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 27 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-14T22:21:33.317Z","repository_id":32822431,"created_at":"2025-08-14T22:21:33.317Z","updated_at":"2025-08-14T22:21:33.317Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":285611836,"owners_count":27201484,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-11-21T02:00:06.175Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-11-16T18:00:29.931Z","updated_at":"2025-11-21T12:02:14.413Z","avatar_url":"https://github.com/EdgedesignCZ.png","language":"XSLT","readme":"\n# PHPQA\n\nAnalyze PHP code with one command.\n\n[![License](https://poser.pugx.org/edgedesign/phpqa/license)](https://packagist.org/packages/edgedesign/phpqa)\n[![Latest Stable Version](https://poser.pugx.org/edgedesign/phpqa/v/stable)](/CHANGELOG.md)\n[![Total Downloads](https://poser.pugx.org/edgedesign/phpqa/downloads)](https://packagist.org/packages/edgedesign/phpqa)\n[![Build Status](https://github.com/EdgedesignCZ/phpqa/workflows/PHPQA%20CI/badge.svg?branch=master)](https://github.com/EdgedesignCZ/phpqa/actions)\n\n## Requirements\n\n- PHP \u003e= 5.4.0\n- `xsl` extension for [HTML reports](#html-reports)\n\n## Why?\n\nEvery analyzer has different arguments and options in different formats *(no surprise in PHP world :)*.\nIf you ever tried to get ignoring directories to work then you know what I mean. On the other hand\nCLI tools are cool because you can analyze any directory or file.\nUnfortunately [Jenkins](http://jenkins-php.org/automation.html),\n[Travis](https://github.com/libis/plugin-Mailer/blob/095cc1154fd6d7beb3be4425329868ecfa2043d9/.travis.yml),\n[Scrutiziner](https://github.com/antonbabenko/imagepush2/blob/db88b1c65a34250ba98e01d584d72421aedfaeac/.scrutinizer.yml)\nneeds special configuration file. What if you want to analyze every bundle in your Symfony app?\nWill you create e.g. Jenkins project/task for each bundle?\n\n* I want to analyze selected directory without complex configuration and creating extra files/tasks\n* I don't care about format of [ignored directories](https://github.com/EdgedesignCZ/phpqa/blob/master/tests/IgnoredPathsTest.php) in phploc, phpmd, ...\n* I don't want to update all projects when QA tool is updated or if I've found cool tool like [PHPMetrics](https://github.com/Halleck45/PhpMetrics)\n* I don't want to analyze XML files → tool should be able to build [html reports](#html-reports)\n* I want fast execution time → tools should run in parallel ([thanks Robo](http://robo.li/tasks/Base/#parallelexec))\n\n## Available [tools](https://github.com/ziadoz/awesome-php#code-analysis)\n\n**Since version [1.27] no tools are preinstalled if you run `composer require`!**\n\nYou have to install relevant composer packages if you want to use them,\nor define `binary` path in `.phpqa.yml`, or use official docker image with preinstalled tools.\n\nTool | PHP | Supported since | Description |\n---- | --- | --------------- | ----------- |\n[phploc](https://github.com/sebastianbergmann/phploc) | `\u003e= 5.4` | `1.0` | Measure the size of a PHP project |\n[phpcpd](https://github.com/sebastianbergmann/phpcpd) | `\u003e= 5.4` | `1.0` | Copy/Paste Detector (CPD) for PHP code |\n[phpcs](https://github.com/squizlabs/PHP_CodeSniffer) | `\u003e= 5.4` | `1.0` | Detect violations of a coding standard |\n[pdepend](https://github.com/pdepend/pdepend) | `\u003e= 5.4` | `1.0` | PHP adaptation of JDepend |\n[phpmd](https://github.com/phpmd/phpmd) | `\u003e= 5.4` | `1.0` | Scan PHP project for messy code |\n[phpmetrics](https://github.com/Halleck45/PhpMetrics) | `\u003e= 5.4` | `1.0` | Static analysis tool for PHP |\n[security-checker](https://github.com/enlightn/security-checker) | `\u003e= 5.6` | `1.24` | Check composer.lock for known security issues |\n[php-cs-fixer](http://cs.sensiolabs.org/) | [`\u003e= 5.3`](https://github.com/EdgedesignCZ/phpqa/pull/66#discussion_r115206573) | `1.12` | Automatically detect and fix PHP coding standards issues |\n[phpunit](https://github.com/phpunit/phpunit) | `\u003e= 5.3` | `1.13` | The PHP Unit Testing framework |\n[phpstan](https://github.com/phpstan/phpstan) | `\u003e= 7.0` | `1.9` | Discover bugs in your code without running it |\n[psalm](https://github.com/vimeo/psalm) | `\u003e= 5.6` | `1.14` | A static analysis tool for finding errors in PHP applications |\n[parallel-lint](https://github.com/JakubOnderka/PHP-Parallel-Lint) | `\u003e= 5.4` | `1.9` | Check syntax of PHP files |\n[deptrac](https://github.com/deptrac/deptrac) | `\u003e= 7.2` | `1.25` | Enforce rules for dependencies between software layers |\n[MacFJA/phpqa-extensions](https://github.com/MacFJA/phpqa-extensions) | - | - | PHP Assumptions, Magic Number Detector, ... |\n\n_Tip_: use [`bin/suggested-tools.sh install`](/bin/suggested-tools.sh) for installing the tools.\n\n## Install\n\n### Clone + composer\n\n```bash\n# install phpqa\ngit clone https://github.com/EdgedesignCZ/phpqa.git \u0026\u0026 cd phpqa \u0026\u0026 composer install --no-dev\n\n# make phpqa globally accessible\n## you can symlink binary\nsudo ln -s /path-to-phpqa-repository/phpqa /usr/bin/phpqa\n## or add this directory to your PATH in your ~/.bash_profile (or ~/.bashrc)\nexport PATH=~/path-to-phpqa-repository-from-pwd:$PATH\n```\n\n### Composer\n\n```bash\n# global installation\ncomposer global require edgedesign/phpqa --update-no-dev\n# Make sure you have ~/.composer/vendor/bin/ in your PATH.\n\n# local installation\ncomposer require edgedesign/phpqa --dev\n```\n\nOf course you can add dependency to `require-dev` section in your `composer.json`.\nBut I wouldn't recommend it. In my experience *one* QA tool which analyzes\n*N* projects is better than *N* projects with *N* analyzers. It's up to you\nhow many repositories you want to update when new version is released.\n\n##### Symfony3 components\n\nSymfony3 is supported since [version 1.7](/CHANGELOG.md#v170).\nInstall at least version `~3.0` of `sebastian/phpcpd`, otherwise you'll get error [`The helper \"progress\" is not defined.`](https://github.com/EdgedesignCZ/phpqa/issues/19)\n\n```json\n{\n    \"require-dev\": {\n        \"edgedesign/phpqa\": \"\u003e=1.7\",\n        \"sebastian/phpcpd\": \"~3.0\"\n    }\n}\n```\n\n##### Fake global installation in local project\n\nDo you have problems with dependencies and you can't install phpqa globally?\nInstall phpqa in [subdirectory](#circleci---artifacts--global-installation).\n\n```bash\n#!/bin/sh\n\nif [ ! -f qa/phpqa ];\nthen\n    echo \"installing phpqa\"\n    (git clone https://github.com/EdgedesignCZ/phpqa.git ./qa  \u0026\u0026 cd qa \u0026\u0026 composer install --no-dev)\nfi\n\nqa/phpqa\n```\n\n### Docker\n\nOfficial docker image repository is https://github.com/EdgedesignCZ/phpqa/pkgs/container/phpqa.\nImages can be used at [Gitlab CI](#gitlabci---docker-installation--composer-cache--artifacts).\n\n```bash\ndocker run --rm -it ghcr.io/edgedesigncz/phpqa:v1.27.1-php7.2 phpqa tools\n# using a tool without phpqa\ndocker run --rm -it ghcr.io/edgedesigncz/phpqa:v1.27.1-php7.2 phploc -v\n```\n\n| Image | PHP version | Tools versions | \n| ----- | ----------- | ----- |\n| `ghcr.io/edgedesigncz/phpqa:v1.27.1-php7.2` | 7.2 | Versions that supports symfony2 components. Not [latest versions](https://github.com/EdgedesignCZ/phpqa/issues/159#issuecomment-452794397). |\n| `ghcr.io/edgedesigncz/phpqa:v1.27.1-php8.1` | 8.1 | |\n| `ghcr.io/edgedesigncz/phpqa:v1.27.1-php8.2` | 8.2 | |\n| `ghcr.io/edgedesigncz/phpqa:v1.27.1-php8.3` | 8.3 | |\n| `ghcr.io/edgedesigncz/phpqa:v1.27.1-php8.4` | 8.4 | |\n| `ghcr.io/edgedesigncz/phpqa:v1.27.1-php8.5` | 8.5 | Generally, latest versions available at the moment. If you need different versions, then [build custom docker image](https://github.com/EdgedesignCZ/phpqa/issues/210) |\n\nBeware that images as lean as possible. That can be a problem for running PHPUnit tests.\nIn that case, you might need different PHP version, miss PHP extensions for database etc.\nYou can [install phpqa](https://gitlab.com/costlocker/integrations/blob/213aab7/.ci/get-phpqa-binary#L40) in another [php image](https://gitlab.com/costlocker/integrations/blob/213aab7/.ci/.gitlab-ci.yml#L28)\nOr [build custom docker image](https://github.com/EdgedesignCZ/phpqa/issues/168#issuecomment-489180974).\n\n```bash\ndocker run --rm -it ghcr.io/edgedesigncz/phpqa:v1.27.1-php7.2 sh -c \"php --version \u0026\u0026 composer --version \u0026\u0026 composer outdated --direct --all \u0026\u0026 phpqa tools\"\ndocker run --rm -it ghcr.io/edgedesigncz/phpqa:v1.27.1-php8.4 sh -c \"php --version \u0026\u0026 composer --version \u0026\u0026 composer outdated --direct --all \u0026\u0026 phpqa tools\"\n```\n\nThere are also available images [eko3alpha/docker-phpqa](https://hub.docker.com/r/eko3alpha/docker-phpqa/) and [sparkfabrik/docker-phpqa](https://hub.docker.com/r/sparkfabrik/docker-phpqa/).\n`phpqa` is used as [an entrypoint](https://docs.docker.com/engine/reference/builder/#entrypoint) (_I haven't been able to use these images at Gitlab CI + [Windows probably needs different environment variable](https://github.com/EdgedesignCZ/phpqa/issues/199#issuecomment-590258608)_).\n\n```bash\ndocker run --rm -u $UID -v $PWD:/app eko3alpha/docker-phpqa --report --ignoredDirs vendor,build,migrations,test\n```\n\n\n\n## Analyze\n\n| Command | Description |\n| ------- | ----------- |\n| `phpqa --help` | Show help - available options, tools, default values, ... |\n| `phpqa --analyzedDirs ./ --buildDir ./build` | Analyze current directory and save output to build directory |\n| `phpqa --analyzedDirs src,tests` | Analyze source and test directory ([phpmetrics analyzes only `src`](#project-with-multiple-directories-src-tests-)) |\n| ~~`phpqa --analyzedDir ./`~~ | Deprecated in **v1.8** in favor of `--analyzedDirs` |\n| `phpqa --ignoredDirs build,vendor` | Ignore directories |\n| `phpqa --ignoredFiles RoboFile.php` | Ignore files |\n| `phpqa --tools phploc,phpcs` | Run only selected tools |\n| `phpqa --tools phpmd:1,phpcs:0,phpcpd:0` | Check number of errors and [exit code](#exit-code). **New in v1.6** |\n| `phpqa --verbose` | Show output from executed tools |\n| `phpqa --quiet` | Show no output at all |\n| `phpqa --output cli` | [CLI output](#output-modes) instead of creating files in `--buildDir` |\n| `phpqa --execution no-parallel` | Don't use parallelism if `--execution != parallel` |\n| `phpqa --config ./my-config` | Use [custom configuration](#advanced-configuration---phpqayml) |\n| `phpqa --report` | Build [html reports](#html-reports) |\n| `phpqa --report offline` | Build html reports with [bundled assets](https://github.com/EdgedesignCZ/phpqa/issues/95). **New in v1.16** |\n| `phpqa tools` | Show versions of available tools |\n\n_Tip:_ CLI options can be defined in [.phpqa.yml](#advanced-configuration---phpqayml)\n\n## Output modes\n\nTool | `--output file` (default) - generated files | `--output cli` |\n---- | ------------------------- | -------------- |\nphploc | [phploc.xml](https://edgedesigncz.github.io/phpqa/report/phploc.xml) | [✓](https://github.com/sebastianbergmann/phploc#analyse-a-directory-and-print-the-result) |\nphpcpd | [phpcpd.xml](https://edgedesigncz.github.io/phpqa/report/phpcpd.xml) | [✓](https://github.com/sebastianbergmann/phpcpd#usage-example) |\nphpcs | [checkstyle.xml](https://edgedesigncz.github.io/phpqa/report/checkstyle.xml) | [full report](https://github.com/squizlabs/PHP_CodeSniffer/wiki/Reporting#printing-full-and-summary-reports) |\npdepend | [pdepend-jdepend.xml](https://edgedesigncz.github.io/phpqa/report/pdepend-jdepend.xml), [pdepend-summary.xml](https://edgedesigncz.github.io/phpqa/report/pdepend-summary.xml), [pdepend-dependencies.xml](https://edgedesigncz.github.io/phpqa/report/pdepend-dependencies.xml), [pdepend-jdepend.svg](https://edgedesigncz.github.io/phpqa/report/pdepend-jdepend.svg), [pdepend-pyramid.svg](https://edgedesigncz.github.io/phpqa/report/pdepend-pyramid.svg) | ✗ |\nphpmd | [phpmd.xml](https://edgedesigncz.github.io/phpqa/report/phpmd.xml) | [✓](https://github.com/phpmd/phpmd/blob/master/src/main/php/PHPMD/Renderer/TextRenderer.php#L47) |\nphpmetrics | [phpmetrics.html (v1)](https://edgedesigncz.github.io/phpqa/report/phpmetrics.html), [phpmetrics/index.html (v2)](https://edgedesigncz.github.io/phpqa/report/phpmetrics/), [phpmetrics.xml](https://edgedesigncz.github.io/phpqa/report/phpmetrics.xml) | [✓](https://github.com/phpmetrics/PhpMetrics#usage) |\nphp-cs-fixer | [php-cs-fixer.html](https://edgedesigncz.github.io/phpqa/report/php-cs-fixer.html) | [✓](http://cs.sensiolabs.org/#usage \"txt output format\") |\nparallel-lint | [parallel-lint.html](https://edgedesigncz.github.io/phpqa/report/parallel-lint.html) | [✓](https://github.com/JakubOnderka/PHP-Parallel-Lint#example-output) |\nphpstan | [phpstan.html](https://edgedesigncz.github.io/phpqa/report/phpstan.html), [phpstan-phpqa.neon](https://edgedesigncz.github.io/phpqa/report/phpstan-phpqa.neon) | [✓](https://edgedesigncz.github.io/phpqa/report/phpstan.html), [phpstan-phpqa.neon](https://edgedesigncz.github.io/phpqa/report/phpstan-phpqa.neon \"Generated configuration is saved in current working directory\") |\npsalm | [psalm.html](https://edgedesigncz.github.io/phpqa/report/psalm.html), [psalm.xml](https://edgedesigncz.github.io/phpqa/report/psalm.xml), [psalm-phpqa.xml](https://edgedesigncz.github.io/phpqa/report/psalm-phpqa.xml) | [✓](https://edgedesigncz.github.io/phpqa/report/psalm.xml), [psalm-phpqa.xml](https://edgedesigncz.github.io/phpqa/report/psalm-phpqa.xml \"Generated configuration is saved in current working directory\") |\ndeptrac | [deptrac.html](https://edgedesigncz.github.io/phpqa/report/deptrac.html) | ✗ |\n\n## Exit code\n\n`phpqa` can return non-zero exit code **since version 1.6**. It's optional feature that is by default turned off.\nYou have to define number of allowed errors for *phpcpd, phpcs, phpmd* in `--tools`.\n\n[mode](#output-modes) | Supported version | What is analyzed? |\n--------------------- | ----------------- | ----------------- |\n`--output file` | \u003e= 1.6 | Number of errors in XML files, or exit code for tools without XML |\n`--output cli` | \u003e= 1.9 | Exit code |\n\nLet's say your [Travis CI](https://docs.travis-ci.com/user/customizing-the-build/#Customizing-the-Build-Step)\nor [Circle CI](https://circleci.com/docs/manually/#overview) build should fail when new error is introduced.\nDefine number of allowed errors for each tools and watch the build:\n\n```bash\nphpqa --report --tools phpcs:0,phpmd:0,phpcpd:0,parallel-lint:0,phpstan:0,phpmetrics,phploc,pdepend\n```\n\nNumber of allowed errors can be also defined in [.phpqa.yml](#advanced-configuration---phpqayml).\n\n```yaml\nphpqa:\n    # can be overriden by CLI: phpqa --tools phpcs:1\n    tools:\n        - phpcs:0\n```\n\n**File mode**\n\n![screenshot from 2016-07-23 13 53 34](https://cloud.githubusercontent.com/assets/7994022/17077767/e18bcb2a-50dc-11e6-86bc-0dfc8e22d98c.png)\n\n_Tip_: override [`phpcs.ignoreWarnings`](#advanced-configuration---phpqayml) if you want to count just errors without phpcs warnings.\n\n**CLI mode**\n\n![screenshot from 2016-12-21 14 31 27](https://cloud.githubusercontent.com/assets/7994022/21391059/33730d76-c78a-11e6-913a-84b3c7836c28.png)\n\n_Tip_: use [`echo $?`](https://gist.github.com/zdenekdrahos/5368eea304ed3fa6070bc77772779738) for displaying exit code.\n\n## Advanced configuration - `.phpqa.yml`\n\nProvide [CLI options](#analyze) from [`.phpqa.yml`](/.phpqa.yml):\n\n| CLI option | .phpqa.yml |\n| ---------- | ---------- |\n| `phpqa --analyzedDirs ./` | `phpqa.analyzedDirs: ./` |\n| `phpqa --buildDir ./build\t` | `phpqa.buildDir: ./build` |\n| `phpqa --ignoredDirs build,vendor` | `phpqa.ignoredDirs: build,vendor` |\n| `phpqa --ignoredFiles RoboFile.php` | `phpqa.ignoredFiles: RoboFile.php` |\n| `phpqa --tools phploc,phpcs:0` | `phpqa.tools: phploc,phpcs:0` |\n| `phpqa --report` | `phpqa.report: true` |\n| `phpqa --execution no-parallel` | `phpqa.execution: no-parallel` |\n| `phpqa --output cli\t` | `phpqa.output: cli` |\n| `phpqa --verbose` | `phpqa.verbose: true` |\n\n### Files\n\n`.phpqa.yml` is automatically detected in current working directory, but you can specify\ndirectory via option:\n\n```bash\n# use .phpqa.yml from defined directory\nphpqa --config path-to-directory-with-config\n```\n\nYou don't have to specify full configuration. Missing or empty values are replaced\nwith default values from our [`.phpqa.yml`](/.phpqa.yml). Example of minimal config\nthat defines only standard for CodeSniffer:\n\n```yaml\nphpcs:\n    standard: Zend\n```\n\n_Tip_: use [PHP Coding Standard Generator](http://edorian.github.io/php-coding-standard-generator/)\nfor generating phpcs/phpmd standards.\n\nYou can specify multiple configurations directory (separated by `,`).\nThey are loaded in the order they are defined.\nThis can be useful if you have a common configuration file that you want to use across multiple project but you still want to have per project configuration.\nAlso, path inside configuration file are relative to where the configuration file is,\nso if you have a package that bundle a custom tool, the `.phpqa.yml` in the package can refers files within it.\n```bash\nphpqa --config ~/phpqa/,my-config/,$(pwd)\n```\n\n### Custom binary\n\nEvery tool can define custom binary. Use phar or global tool, if you have troubles with dependencies, e.g.:\n\n* can't install something because of symfony components or php version\n* phpstan does not work, if phpmetrics v1 is installed in composer _(`Hoa main file (Core.php) must be included once.`)_ -\u003e use phar for phpmetrics\n\nGenerally, composer installation is preferred because of detecting version.\nPhar works too, but it might be tricky. If a tool has composer package with phar\n_(e.g. [vimeo/phar](https://packagist.org/packages/psalm/phar))_, use it instead of custom binary:\n\n```yaml\npsalm:\n    binary: /usr/local/bin/psalm.phar\n```\n\nPossibilities are infinite. You can [define new tool](https://github.com/EdgedesignCZ/phpqa/blob/master/.phpqa.yml#L120)\nand run it. For example I like `exploring codebase` in phpmetrics v1 and composer info in v2.\nInstall phpmetrics v2 in composer and use phar for v1 to avoid phpstan conflicts:\n\n```bash\n$ cat tests/.ci/.phpqa.yml\nphpmetricsV1:\n    binary: /usr/local/bin/phpmetrics.phar\ntool:\n    phpmetricsV1: Edge\\QA\\Tools\\Analyzer\\PhpMetrics\n\n$ phpqa --config tests/.ci/ --tools phpmetricsV1,phpmetrics\n```\n\n### Override tools' settings\n\nTool | Settings | Default Value | Your value\n---- | -------- | ------------- | ----------- |\n[phpqa.extensions](https://github.com/EdgedesignCZ/phpqa/blob/master/.phpqa.yml#L49) | PHP File extensions | php | Name of php file to parse, you can specify it like a string `php,inc,modules` or like a yaml array.\n[phpcs.standard](https://pear.php.net/manual/en/package.php.php-codesniffer.usage.php#package.php.php-codesniffer.usage.coding-standard) | Coding standard | PSR2 | Name of existing standard (`PEAR`, `PHPCS`, `PSR1`, `PSR2`, `Squiz`,  `Zend`), or path to your coding standard. To specify [multiple standards](https://github.com/squizlabs/PHP_CodeSniffer/wiki/Usage#specifying-a-coding-standard), you can use an array\n[phpcs.ignoreWarnings](https://github.com/EdgedesignCZ/phpqa/issues/53) | If number of allowed errors is compared with warnings+errors, or just errors from `checkstyle.xml` | `false` | Boolean value\n[phpcs.reports](https://github.com/squizlabs/PHP_CodeSniffer/wiki/Reporting) | Report types | [`full`](https://github.com/squizlabs/PHP_CodeSniffer/wiki/Reporting#printing-full-and-summary-reports) report in [cli mode](#output-modes), [`checkstyle`](https://github.com/squizlabs/PHP_CodeSniffer/wiki/Reporting#printing-a-checkstyle-report) in [file mode](#output-modes) | Predefined [report types](https://github.com/squizlabs/PHP_CodeSniffer/wiki/Reporting) or [custom reports](https://github.com/wikidi/codesniffer#examples)\n[php-cs-fixer.rules](http://cs.sensiolabs.org/#usage) | Coding standard rules | `@PSR2` | String value\n[php-cs-fixer.allowRiskyRules](http://cs.sensiolabs.org/#usage) | Whether risky rules may run  | `false` | Boolean value\n[php-cs-fixer.config](http://cs.sensiolabs.org/#usage) | Load configuration from [file](https://github.com/FriendsOfPHP/PHP-CS-Fixer/blob/master/.php_cs.dist) | `null` | Path to `.phpcs` file\n[php-cs-fixer.isDryRun](http://cs.sensiolabs.org/#usage) | If code is just analyzed or fixers are applied  | `true` | Boolean value\n[phpmetrics.config](https://github.com/EdgedesignCZ/phpqa/issues/74) | Configuration for phpmetrics v1  | `null` | Path to `.phpmetrics.yml` file\n[phpmetrics.git](https://github.com/EdgedesignCZ/phpqa/pull/122) | phpmetrics v2 analyses based on Git History   | `null` | Boolean value or path to git binary\n[phpmetrics.junit](https://github.com/EdgedesignCZ/phpqa/pull/125) | phpmetrics v2 evaluates metrics according to JUnit logs | `null` | Path to JUnit xml\n[phpmetrics.composer](https://github.com/EdgedesignCZ/phpqa/pull/123) | phpmetrics v2 analyzes composer dependencies | `null` | Path to composer.json when the file is not included in `analyzedDirs`\n[pdepend.coverageReport](https://github.com/EdgedesignCZ/phpqa/pull/124) | Load Clover style CodeCoverage report | `null` | Path to report produced by PHPUnit's `--coverage-clover` option\n[phpmd.standard](http://phpmd.org/documentation/creating-a-ruleset.html) | Ruleset | [Edgedesign's standard](/app/phpmd.xml) | Path to ruleset. To specify [multiple rule sets](https://phpmd.org/documentation/index.html#using-multiple-rule-sets), you can use an array\n[phpmd.ignoreParsingErrors](https://github.com/EdgedesignCZ/phpqa/issues/230) | If parsing errors affect exit code, or just violations | `true` | Boolean value\n[phpcpd](https://github.com/sebastianbergmann/phpcpd/blob/de9056615da6c1230f3294384055fa7d722c38fa/src/CLI/Command.php#L136) | Minimum number of lines/tokens for copy-paste detection | 5 lines, 70 tokens |\n[phpstan](https://github.com/phpstan/phpstan#configuration) | Level, error format, config file, memory limit | Level 0, checkstyle, `%currentWorkingDirectory%/phpstan.neon`, memoryLimit: null | Take a look at [phpqa config in tests/.ci](/tests/.ci/) |\n[phpunit.binary](https://github.com/EdgedesignCZ/phpqa/blob/4947416/.phpqa.yml#L40) | Phpunit binary  | phpqa's phpunit | Path to phpunit executable in your project, typically [`vendor/bin/phpunit`](https://gitlab.com/costlocker/integrations/blob/master/basecamp/backend/.phpqa.yml#L2) |\n[phpunit.config](https://phpunit.de/manual/current/en/organizing-tests.html#organizing-tests.xml-configuration) | PHPUnit configuration, `analyzedDirs` and `ignoredDirs` are not used, you have to specify test suites in XML file | `null` | Path to `phpunit.xml` file\n[phpunit.reports](https://phpunit.de/manual/current/en/textui.html) | Report types  | no report | List of reports and formats, corresponds with CLI option, e.g. `--log-junit` is `log: [junit]` in `.phpqa.yml` |\n[psalm.config](https://psalm.dev/docs/running_psalm/configuration/) | Psalm configuration, `analyzedDirs` and `ignoredDirs` are appended to `projectFiles` | [Predefined config](/app/psalm.xml) | Path to `psalm.xml` file\n[psalm.deadCode](https://psalm.dev/docs/running_psalm/issues/UnusedClass/) | Enable or not `--find-dead-code` option  of psalm | `false` | Boolean value\n[psalm.threads](https://psalm.dev/docs/running_psalm/command_line_usage/#running-psalm-faster) | Set the number of process to use in parallel (option `--threads` of psalm) (Only if `--execution == parallel` for phpqa) | `1` | Number (\u003e= 1)\n[psalm.showInfo](https://psalm.dev/docs/running_psalm/configuration/#reportinfo) | Display or not information (non-error) messages (option `--show-info=` of psalm) | `true` | Boolean value\n[psalm.memoryLimit](https://github.com/vimeo/psalm/issues/842) | Custom memory limit, ignore unless you are getting `Fatal error: Allowed memory size of ... bytes exhausted` | `null` | String value, e.g. `'1024M'`, `'1G'`\n[deptrac.depfile](https://deptrac.github.io/deptrac/#configuration) | Complete [deptrac config](https://deptrac.github.io/deptrac/configuration/) _(phpqa won't update source and excluded files)_ | `null` | Path to `deptrac.yml` file\n[deptrac.reportUncovered](https://deptrac.github.io/deptrac/concepts/#uncovered-dependencies) | Option to let you know about any uncovered dependencies | `true` | Boolean value\n[security-checker.composerLock](https://github.com/EdgedesignCZ/phpqa/blob/bdd49e3/.phpqa.yml#L94) | Use it if composer.lock is not in current working directory or analyzed directory | `null` | Path to `composer.lock` file\n\n## HTML reports\n\nIf you don't have Jenkins or other CI server, then you can use HTML reports.\nHTML files are built when you add option `--report`. Take a look at\n[report from phpqa](https://edgedesigncz.github.io/phpqa/report/phpqa.html).\n\n```bash\n# build html reports\nphpqa --report\n```\n\n### Custom templates\n\nDefine custom templates if you don't like [default templates](/app/report).\nYou have to define path to `xsl` files in your [`.phpqa.yml`](#advanced-configuration---phpqayml):\n\n```yaml\n# use different template for PHPMD, use default for other tools\nreport:\n    phpmd: my-templates/phpmd.xsl\n```\n\nBe aware that all **paths are relative to `.phpqa.yml`**. Don't copy-paste section `report`\nif you don't have custom templates!\n\n### Requirements\n\n[`xsl` extension](http://php.net/manual/en/class.xsltprocessor.php)\nmust be installed and enabled for exporting HTML reports.\nOtherwise you'll get error `PHP Fatal error:  Class 'XSLTProcessor' not found`.\n\n```bash\n# install xsl extension in Ubuntu\nsudo apt-get update\nsudo apt-get install php5-xsl\nsudo service apache2 restart\n```\n\n## Continuous integration\n\nWe use [Jenkins-CI](http://jenkins-php.org/) in Edgedesign. Below you can find examples of\n[Phing](https://www.phing.info/), [Robo](http://robo.li/) and `bash` tasks.\n\n### Project with one directory\n\nTypically in Symfony project you have project with `src` directory with all the code and tests. So you don't need ignore vendors, web directory etc.\n\n**Phing - `build.xml`**\n\n```xml\n\u003ctarget name=\"ci-phpqa\"\u003e\n    \u003cexec executable=\"phpqa\" passthru=\"true\"\u003e\n        \u003carg value=\"--analyzedDirs=./src\" /\u003e\n        \u003carg value=\"--buildDir=./build/logs\" /\u003e\n        \u003carg value=\"--report\" /\u003e\n    \u003c/exec\u003e\n\u003c/target\u003e\n```\n\n**Robo - `RoboFile.php`**\n\n```php\npublic function ciPhpqa()\n{\n    $this-\u003etaskExec('phpqa')\n        -\u003eoption('analyzedDirs', './src')\n        -\u003eoption('buildDir', './build/logs')\n        -\u003eoption('report')\n        -\u003erun();\n}\n```\n\n### Project with multiple directories (src, tests, ...)\n\nWhen you analyze root directory of your project don't forget to ignore vendors and\nother non-code directories. Otherwise the analysis could take a very long time.\n\n**Since version [1.8](CHANGELOG.md#v180) phpqa supports analyzing multiple directories.**\nExcept phpmetrics that analyzes only first directory. Analyze root directory and ignore other directories if you rely on phpmetrics report.\n\n**Phing - `build.xml`**\n\n```xml\n\u003ctarget name=\"ci-phpqa\"\u003e\n    \u003cexec executable=\"phpqa\" passthru=\"true\"\u003e\n        \u003carg value=\"--analyzedDirs=./\" /\u003e\n        \u003carg value=\"--buildDir=./build/logs\" /\u003e\n        \u003carg value=\"--ignoredDirs=app,bin,build,vendor,web\" /\u003e\n        \u003carg value=\"--ignoredFiles= \" /\u003e\n        \u003carg value=\"--verbose\" /\u003e\n        \u003carg value=\"--report\" /\u003e\n    \u003c/exec\u003e\n\u003c/target\u003e\n```\n\n**Robo - `RoboFile.php`**\n\n```php\npublic function ciPhpqa()\n{\n    $this-\u003etaskExec('phpqa')\n        -\u003eoption('verbose')\n        -\u003eoption('report')\n        -\u003eoption('analyzedDirs', './')\n        -\u003eoption('buildDir', './build')\n        -\u003eoption('ignoredDirs', 'build,bin,vendor')\n        -\u003eoption('ignoredFiles', 'RoboFile.php,error-handling.php')\n        -\u003erun();\n}\n```\n\n**Bash**\n\n```bash\nphpqa --verbose --report --analyzedDirs ./ --buildDir ./var/CI --ignoredDirs=bin,log,temp,var,vendor,www\n```\n\n### Circle.ci - artifacts + global installation\n\n```yaml\nmachine:\n    php:\n        version: 7.0.4\n\ndependencies:\n    cache_directories:\n        - ~/.composer/cache\n    post:\n        - 'git clone https://github.com/EdgedesignCZ/phpqa.git ./qa \u0026\u0026 cd qa \u0026\u0026 composer install --no-dev'\n\ntest:\n    override:\n        - vendor/bin/phpunit --testdox-html ./var/tests/testdox.html --testdox-text ./var/tests/testdox.txt --log-junit $CIRCLE_TEST_REPORTS/phpunit/junit.xml\n        - qa/phpqa --report --verbose --buildDir var/QA --ignoredDirs vendor --tools=phpcs:0,phpmd:0,phpcpd:0,phploc,pdepend,phpmetrics\n    post:\n        - cp -r ./var/QA $CIRCLE_ARTIFACTS\n        - cp -r ./var/tests $CIRCLE_ARTIFACTS\n```\n\n### Gitlab.ci - docker installation + composer cache + artifacts\n\n```yaml\nstages:\n  - test\n\ntest:\n  stage: test\n  image: ghcr.io/edgedesigncz/phpqa:v1.27.1-php7.2\n  variables:\n    BACKEND_QA: \"*/backend/var/QA\"\n    BACKEND_CACHE: $CI_PROJECT_DIR/.composercache\n  cache:\n    paths:\n    - $BACKEND_CACHE\n  script:\n    - 'export COMPOSER_CACHE_DIR=$BACKEND_CACHE'\n    - 'composer install --ignore-platform-reqs --no-progress --no-suggest'\n    - 'phpqa --report --tools phpcs:0,phpunit:0 --buildDir var/QA --analyzedDirs ./ --ignoredDirs var,vendor'\n  artifacts:\n    when: always\n    paths:\n    - $BACKEND_QA\n```\n\n### Github actions - docker installation + composer cache + artifacts\n\n```yaml\nname: QA\n\non: [push]\n\njobs:\n  qa:\n    container: ghcr.io/edgedesigncz/phpqa:v1.27.1-php8.4\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      \n      # composer is not necessary, if you are not running phpunit/psalm/phpstan\n      - name: Cache composer\n        uses: actions/cache@v2\n        with:\n          path: |\n            ~/.composer/cache\n            vendor\n          key: php-composer-${{ hashFiles('**/composer.lock') }}\n          restore-keys: \"php-composer-74\"\n      - name: Install dependencies\n        run: |\n          composer install --no-interaction --no-progress --ignore-platform-reqs;\n\n      - name: phpqa\n        run: phpqa --report --tools phpunit:0,phpcs:0,phpmd:0,psalm:0,phpstan:0 --buildDir build --analyzedDirs ./ --ignoredDirs build,vendor\n\n      - name: Upload QA files\n        uses: actions/upload-artifact@v2\n        with:\n          name: phpqa\n          path: build\n```\n\n## Contributing\n\nContributions from others would be very much appreciated! Send\n[pull request](https://github.com/EdgedesignCZ/phpqa/pulls)/[issue](https://github.com/EdgedesignCZ/phpqa/issues). Thanks!\n\n## License\n\nCopyright (c) 2015 - present Edgedesign.cz. MIT Licensed,\nsee [LICENSE](/LICENSE) for details.\n\n","funding_links":[],"categories":["Programming Languages"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/edgedesigncz.github.io%2Fphpqa%2F","html_url":"https://awesome.ecosyste.ms/projects/edgedesigncz.github.io%2Fphpqa%2F","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/edgedesigncz.github.io%2Fphpqa%2F/lists"}