├── .devcontainer └── devcontainer.json ├── .dockerignore ├── .github └── workflows │ ├── devcontainer.yml │ ├── docker.yml │ └── frankenphp.yml ├── .gitignore ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── bin ├── co-phpunit ├── composer ├── composer-require-checker ├── couscous ├── deptrac ├── exakat ├── frankenphp ├── infection ├── notty ├── pest ├── php ├── php-cs-fixer ├── phpcbf ├── phpcs ├── phpctl ├── phpmd ├── phpstan ├── phpunit ├── pint ├── rector └── watchr ├── bundle ├── Dockerfile ├── bin.sh └── docker-entrypoint.sh ├── docs ├── CNAME ├── _config.yml ├── commands.md ├── extensions.md ├── index.md ├── install.sh ├── phpctlini.md ├── phpctlrc.md ├── uninstall.sh └── why.md ├── examples ├── README.md ├── box │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── composer.json │ ├── composer.lock │ └── main ├── bundle │ ├── .gitignore │ ├── Makefile │ ├── README.md │ └── main.php ├── frankenphp │ └── public │ │ └── index.php ├── pest │ ├── .gitignore │ ├── Makefile │ ├── composer.json │ ├── composer.lock │ ├── phpunit.xml │ └── tests │ │ ├── Feature │ │ └── ExampleTest.php │ │ ├── Pest.php │ │ ├── TestCase.php │ │ └── Unit │ │ └── ExampleTest.php ├── phpctl.ini │ └── phpctl.ini ├── phpctlrc │ └── .phpctlrc ├── phpmd │ ├── .gitignore │ ├── README.md │ ├── composer.json │ ├── composer.lock │ └── src │ │ └── Example.php ├── phpunit │ ├── .gitignore │ ├── README.md │ ├── composer.json │ ├── composer.lock │ ├── phpunit.xml │ ├── src │ │ └── Example.php │ └── tests │ │ └── ExampleTest.php ├── rector │ ├── .gitignore │ ├── README.md │ ├── composer.json │ ├── composer.lock │ ├── rector.php │ └── src │ │ └── example.php ├── server │ └── index.php ├── swoole │ ├── .gitignore │ ├── composer.json │ ├── composer.lock │ └── server.php └── xdebug │ ├── README.md │ └── phpctl.ini ├── frankenphp.Dockerfile ├── lib └── bashunit ├── php.ini ├── rootfs ├── etc │ └── php │ │ └── php.ini └── usr │ └── local │ └── bin │ ├── install-swoole │ └── install-tools ├── scripts └── symlink-bins.sh ├── skeletons ├── .php-cs-fixer.php ├── box.json ├── infection.json5 ├── phpstan.neon └── phpunit.xml ├── src-devc ├── .devcontainer │ ├── Dockerfile │ └── devcontainer.json └── build.sh ├── src ├── bundle.sh ├── docker.sh ├── doctor.sh ├── frankenphp.sh ├── help.sh ├── php.sh ├── scaffold.sh ├── self-update.sh ├── sh.sh └── tools.sh └── tests ├── doctor_test.sh ├── help_test.sh ├── install ├── Makefile ├── README.md ├── alpine.Dockerfile ├── archlinux.Dockerfile ├── build ├── docker-entrypoint.sh ├── test └── ubuntu.Dockerfile ├── php_test.sh ├── sh_test.sh └── tools_test.sh /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "image": "opencodeco/phpctl:php83-devcontainer", 3 | "containerEnv": { 4 | "PHP_VERSION": "83" 5 | }, 6 | "features": { 7 | "ghcr.io/devcontainers/features/docker-in-docker:2": {}, 8 | "ghcr.io/devcontainers-contrib/features/devcontainers-cli:1": {}, 9 | "ghcr.io/devcontainers/features/sshd:1": {}, 10 | "ghcr.io/devcontainers-contrib/features/apt-get-packages:1": { 11 | "packages": "parallel" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | ** 2 | !rootfs/ 3 | -------------------------------------------------------------------------------- /.github/workflows/devcontainer.yml: -------------------------------------------------------------------------------- 1 | name: Dev Container 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | devcontainer: 11 | runs-on: ubuntu-latest 12 | strategy: 13 | matrix: 14 | include: 15 | - php: 81 16 | php-str: 8.1 17 | - php: 82 18 | php-str: 8.2 19 | - php: 83 20 | php-str: 8.3 21 | 22 | steps: 23 | - 24 | name: Checkout 25 | uses: actions/checkout@v3 26 | - 27 | name: Set up QEMU 28 | uses: docker/setup-qemu-action@v3 29 | - 30 | name: Set up Docker Buildx 31 | uses: docker/setup-buildx-action@v3 32 | - 33 | name: Login to Docker Hub 34 | uses: docker/login-action@v3 35 | with: 36 | username: ${{ secrets.DOCKERHUB_USERNAME }} 37 | password: ${{ secrets.DOCKERHUB_TOKEN }} 38 | - 39 | name: Build and run dev container task 40 | uses: devcontainers/ci@v0.3 41 | env: 42 | PHP_VERSION: ${{ matrix.php }} 43 | PHP_VERSION_STR: ${{ matrix.php-str }} 44 | with: 45 | subFolder: src-devc 46 | imageName: opencodeco/phpctl 47 | imageTag: php${{ matrix.php }}-devcontainer 48 | push: always 49 | -------------------------------------------------------------------------------- /.github/workflows/docker.yml: -------------------------------------------------------------------------------- 1 | name: Docker 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | docker: 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | include: 14 | - alpine: '3.19' 15 | php: 81 16 | without-watchr: 1 17 | - alpine: '3.20' 18 | php: 82 19 | without-watchr: '' 20 | - alpine: '3.20' 21 | php: 83 22 | without-watchr: '' 23 | steps: 24 | - 25 | name: Checkout 26 | uses: actions/checkout@v3 27 | - 28 | name: Set up QEMU 29 | uses: docker/setup-qemu-action@v3 30 | - 31 | name: Set up Docker Buildx 32 | uses: docker/setup-buildx-action@v3 33 | - 34 | name: Login to Docker Hub 35 | uses: docker/login-action@v3 36 | with: 37 | username: ${{ secrets.DOCKERHUB_USERNAME }} 38 | password: ${{ secrets.DOCKERHUB_TOKEN }} 39 | - 40 | name: Build and export to Docker 41 | uses: docker/build-push-action@v5 42 | with: 43 | context: . 44 | load: true 45 | build-args: | 46 | ALPINE=${{ matrix.alpine }} 47 | PHP=${{ matrix.php }} 48 | WITHOUT_WATCHR=${{ matrix.without-watchr }} 49 | tags: opencodeco/phpctl:php${{ matrix.php }} 50 | - 51 | name: Test 52 | env: 53 | PHP_VERSION: ${{ matrix.php }} 54 | PHPCTL_TTY: --label=no-tty 55 | WITHOUT_WATCHR: ${{ matrix.without-watchr }} 56 | run: | 57 | ./lib/bashunit ./tests/ 58 | - 59 | name: Build and push 60 | uses: docker/build-push-action@v5 61 | with: 62 | context: . 63 | push: true 64 | build-args: | 65 | ALPINE=${{ matrix.alpine }} 66 | PHP=${{ matrix.php }} 67 | tags: opencodeco/phpctl:php${{ matrix.php }} 68 | -------------------------------------------------------------------------------- /.github/workflows/frankenphp.yml: -------------------------------------------------------------------------------- 1 | name: FrankenPHP 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | frankenphp: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - 14 | name: Checkout 15 | uses: actions/checkout@v3 16 | - 17 | name: Set up QEMU 18 | uses: docker/setup-qemu-action@v3 19 | - 20 | name: Set up Docker Buildx 21 | uses: docker/setup-buildx-action@v3 22 | - 23 | name: Login to Docker Hub 24 | uses: docker/login-action@v3 25 | with: 26 | username: ${{ secrets.DOCKERHUB_USERNAME }} 27 | password: ${{ secrets.DOCKERHUB_TOKEN }} 28 | - 29 | name: Build and push 30 | uses: docker/build-push-action@v5 31 | with: 32 | context: . 33 | file: frankenphp.Dockerfile 34 | push: true 35 | tags: opencodeco/phpctl:frankenphp 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Feel free to contribute to this project by submitting a pull request to the `main` branch. 4 | 5 | ## Developing 6 | 7 | You can use `make` to simplify the development process. 8 | 9 | > [!NOTE] 10 | > Make sure you have [GNU/Parallel](https://www.gnu.org/software/parallel/) installed to speed up processes for each PHP version. 11 | 12 | ### Building 13 | You can build the default image using `make build` or just `make`, the `build` target is the default: 14 | ```shell 15 | make 16 | ``` 17 | 18 | ### Testing 19 | To run the tests, you can use the `test` target: 20 | ```shell 21 | make test 22 | ``` 23 | 24 | > [!TIP] 25 | > So you will problably be running `make && make test` for most of the time. 26 | 27 | ### Installing 28 | You can use the `install` target to make links of the binaries (`bin/`) to your `/usr/local/bin` directory: 29 | ```shell 30 | make install 31 | ``` 32 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG ALPINE=3.20 2 | FROM alpine:$ALPINE 3 | 4 | ARG PHP 5 | ENV PHP_VERSION=$PHP 6 | 7 | ARG WITH_EXAKAT 8 | ENV WITH_EXAKAT=$WITH_EXAKAT 9 | 10 | ARG WITHOUT_WATCHR 11 | ENV WITHOUT_WATCHR=$WITHOUT_WATCHR 12 | 13 | COPY rootfs / 14 | RUN apk update && apk upgrade && apk add --no-cache \ 15 | git \ 16 | docker-cli \ 17 | php${PHP}-cli \ 18 | php${PHP}-ctype \ 19 | php${PHP}-curl \ 20 | php${PHP}-dom \ 21 | php${PHP}-ffi \ 22 | php${PHP}-fileinfo \ 23 | php${PHP}-gd \ 24 | php${PHP}-iconv \ 25 | php${PHP}-mbstring \ 26 | php${PHP}-mysqlnd \ 27 | php${PHP}-openssl \ 28 | php${PHP}-pcntl \ 29 | php${PHP}-pdo \ 30 | php${PHP}-pdo_mysql \ 31 | php${PHP}-pdo_pgsql \ 32 | php${PHP}-phar \ 33 | php${PHP}-posix \ 34 | php${PHP}-simplexml \ 35 | php${PHP}-sodium \ 36 | php${PHP}-sqlite3 \ 37 | php${PHP}-tokenizer \ 38 | php${PHP}-xml \ 39 | php${PHP}-xmlreader \ 40 | php${PHP}-xmlwriter \ 41 | php${PHP}-zip \ 42 | php${PHP}-pecl-decimal \ 43 | php${PHP}-pecl-ds \ 44 | php${PHP}-pecl-mongodb \ 45 | php${PHP}-pecl-pcov \ 46 | php${PHP}-pecl-rdkafka \ 47 | php${PHP}-pecl-redis \ 48 | php${PHP}-pecl-swoole \ 49 | php${PHP}-pecl-xdebug \ 50 | && ln -sf /usr/bin/php${PHP} /usr/bin/php \ 51 | && mv /etc/php/php.ini /etc/php${PHP}/conf.d/zzphp.ini \ 52 | && /usr/local/bin/install-tools 53 | ARG HOST_USER 54 | RUN apk add doas; \ 55 | adduser ${HOST_USER}; \ 56 | echo "${HOST_USER}" | chpasswd; \ 57 | echo "permit ${HOST_USER} as root" > /etc/doas.d/doas.conf 58 | ENTRYPOINT [ "/usr/bin/php" ] 59 | CMD [ "-v" ] 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 OpenCodeCo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: default 2 | default: build 3 | 4 | .PHONY: build 5 | build: 6 | @parallel --line-buffer PHP_VERSION={} ./bin/phpctl build ::: 81 82 83 7 | 8 | .PHONY: test 9 | test: 10 | @parallel --line-buffer PHP_VERSION={} COMPOSER_AUTH= TERM= ./bin/notty ./lib/bashunit ./tests/ ::: 81 82 83 11 | @[ -f phpctl.ini ] && rm phpctl.ini 12 | 13 | .PHONY: install 14 | install: 15 | @sudo ./scripts/symlink-bins.sh 16 | 17 | .PHONY: devcontainers 18 | devcontainers: 19 | @parallel --line-buffer PHP_VERSION={} ./src-devc/build.sh ::: 81 82 83 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 17 | 18 |
4 | phpctl logo 5 | 7 |

8 | phpctl 9 | phpctl docker badge 10 | phpctl docker badge 11 | phpctl frankenphp badge 12 |

13 |

🐳 A Docker-based development environment for PHP 🐘

14 |
Heavily inspired by opencodeco/hfctl.
15 |

Open in GitHub Codespaces

16 |
19 | 20 | ## Frictionless PHP Development 21 | 22 | Seamlessly run and switch between different versions of PHP, with different installed extensions, thanks to the power of containers. 23 | Take the advantage of goodie commands like `phpctl create` to start a new project, `phpctl repl` to start a REPL, `phpctl init` to initialize a new configuration file **and a lot more**. 24 | 25 | ### Just install 26 | ```shell 27 | /bin/bash -c "$(curl -fsSL https://phpctl.dev/install.sh)" 28 | ``` 29 | ### And that is it! 30 | Try it out: 31 | ```shell 32 | phpctl doctor 33 | php --version 34 | composer --version 35 | ``` 36 | 37 | Using [Dev Containers](https://containers.dev/)? We have a pre-built image: 38 | ```json 39 | { 40 | "image": "opencodeco/phpctl:php83-devcontainer" 41 | } 42 | ``` 43 | In fact, we use it ourselves to develop `phpctl` itself: [devcontainer.json](.devcontainer/devcontainer.json). 44 | 45 | 46 | ## Getting started 47 | 48 | - [Installation guide](https://phpctl.dev/#installation) 49 | - [How to use](https://phpctl.dev/#usage) 50 | - [Available commands](https://phpctl.dev/commands) 51 | - [The `.phpctlrc` file](https://phpctl.dev/phpctlrc) 52 | - [The `phpctl.ini` file](https://phpctl.dev/phpctlini) 53 | - [Available extensions](https://phpctl.dev/extensions) 54 | - [Why it exists?](https://phpctl.dev/why) 55 | 56 | ## Contributing 57 | Click here to read the [contributing guidelines](CONTRIBUTING.md). 58 | -------------------------------------------------------------------------------- /bin/co-phpunit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | phpctl co-phpunit $@ 3 | -------------------------------------------------------------------------------- /bin/composer: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | phpctl composer $@ 3 | -------------------------------------------------------------------------------- /bin/composer-require-checker: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | phpctl composer-require-checker $@ 3 | -------------------------------------------------------------------------------- /bin/couscous: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | phpctl couscous $@ 3 | -------------------------------------------------------------------------------- /bin/deptrac: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | phpctl deptrac $@ 3 | -------------------------------------------------------------------------------- /bin/exakat: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | phpctl exakat $@ 3 | -------------------------------------------------------------------------------- /bin/frankenphp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | phpctl frankenphp $@ 3 | -------------------------------------------------------------------------------- /bin/infection: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | phpctl infection $@ 3 | -------------------------------------------------------------------------------- /bin/notty: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | PHPCTL_TTY="--label=no-tty" $@ 3 | -------------------------------------------------------------------------------- /bin/pest: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | phpctl pest $@ 3 | -------------------------------------------------------------------------------- /bin/php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | phpctl php $@ 3 | -------------------------------------------------------------------------------- /bin/php-cs-fixer: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | phpctl php-cs-fixer $@ 3 | -------------------------------------------------------------------------------- /bin/phpcbf: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | phpctl phpcbf $@ 3 | -------------------------------------------------------------------------------- /bin/phpcs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | phpctl phpcs $@ 3 | -------------------------------------------------------------------------------- /bin/phpctl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | PHPCTL_DIR=$(dirname "$(realpath "$0")")/../ 3 | 4 | if [ -s "$HOME/.phpctlrc" ]; then 5 | set -a 6 | . "$HOME/.phpctlrc" 7 | set +a 8 | fi 9 | 10 | if [ -s .phpctlrc ]; then 11 | set -a 12 | . .phpctlrc 13 | set +a 14 | fi 15 | 16 | PHP_VERSION=${PHP_VERSION:-82} 17 | PHPCTL_IMAGE=${PHPCTL_IMAGE:-opencodeco/phpctl:php$PHP_VERSION} 18 | PHPCTL_TTY=${PHPCTL_TTY:--it} 19 | PHPCTL_RUNTIME=${PHPCTL_RUNTIME:-detect} 20 | PHPCTL_USER=${PHPCTL_USER:-root} 21 | 22 | if [ "${PHPCTL_RUNTIME}" == "detect" ]; then 23 | PHPCTL_RUNTIME= 24 | if command -v docker > /dev/null 2>&1; then 25 | PHPCTL_RUNTIME=docker 26 | elif command -v podman > /dev/null 2>&1; then 27 | PHPCTL_RUNTIME=podman 28 | else 29 | echo "Could not find neither \"docker\" nor \"podman\", aborting" 30 | exit 1 31 | fi 32 | fi 33 | 34 | for file in "$PHPCTL_DIR"/src/*.sh; do 35 | # shellcheck source=src/php.sh 36 | . "$file" 37 | done 38 | 39 | ${1:-help} "${@:2}" 40 | -------------------------------------------------------------------------------- /bin/phpmd: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | phpctl phpmd $@ 3 | -------------------------------------------------------------------------------- /bin/phpstan: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | phpctl phpstan $@ 3 | -------------------------------------------------------------------------------- /bin/phpunit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | phpctl phpunit $@ 3 | -------------------------------------------------------------------------------- /bin/pint: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | phpctl pint $@ 3 | -------------------------------------------------------------------------------- /bin/rector: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | phpctl rector $@ 3 | -------------------------------------------------------------------------------- /bin/watchr: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | phpctl watchr $@ 3 | -------------------------------------------------------------------------------- /bundle/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG FROM=opencodeco/phpctl:php82 2 | FROM $FROM 3 | ARG ENTRYPOINT=php 4 | ENV ENTRYPOINT=$ENTRYPOINT 5 | ARG COMMAND=index.php 6 | ENV COMMAND=$COMMAND 7 | COPY . /usr/src 8 | ENTRYPOINT [ "/usr/src/docker-entrypoint.sh" ] 9 | -------------------------------------------------------------------------------- /bundle/bin.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | : ' 3 | This script file was generated by the phpctl bundle command. 4 | It is basically a wrapper around the docker run command. 5 | It is not intended to be edited, but feel free to do so (if you know what you are doing). 6 | Move this script file to somewhere in your PATH to make it available as a command. 7 | A good place would be /usr/local/bin. 8 | ' 9 | # shellcheck disable=SC2046 10 | ${CONTAINER_RUNTIME-docker} run \ 11 | -w /usr/local/src \ 12 | -v "$PWD":/usr/local/src \ 13 | --net host \ 14 | $(env | awk -F= '/^[[:alpha:]]/{print $1}' | sed 's/^/-e/') \ 15 | --rm -it IMAGE $@ 16 | -------------------------------------------------------------------------------- /bundle/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | "$ENTRYPOINT" "/usr/src/$COMMAND" $@ 3 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | phpctl.dev -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | title: phpctl 2 | description: Frictionless PHP Development 3 | remote_theme: just-the-docs/just-the-docs 4 | url: https://phpctl.dev 5 | repository: https://github.com/opencodeco/phpctl 6 | permalink: pretty 7 | 8 | aux_links: 9 | phpctl on GitHub: 10 | - https://github.com/opencodeco/phpctl 11 | 12 | nav_external_links: 13 | - title: phpctl on GitHub 14 | url: https://github.com/opencodeco/phpctl 15 | 16 | back_to_top: true 17 | back_to_top_text: "Back to top" 18 | 19 | gh_edit_link: true 20 | gh_edit_link_text: Edit this page on GitHub 21 | gh_edit_repository: https://github.com/opencodeco/phpctl 22 | gh_edit_branch: main 23 | gh_edit_source: docs 24 | gh_edit_view_mode: tree 25 | 26 | plugins: 27 | - jekyll-remote-theme 28 | - jekyll-seo-tag 29 | - jekyll-github-metadata 30 | -------------------------------------------------------------------------------- /docs/commands.md: -------------------------------------------------------------------------------- 1 | --- 2 | nav_order: 2 3 | --- 4 | 5 | # Available commands 6 | 7 | ## Developing 8 | 9 | | Command | Description | 10 | |:-----------------------------|:---------------------------------------------------------------------------------------------| 11 | | `php` | **Runs PHP commands** (`phpctl php -v` or `phpctl php -m`). | 12 | | `composer` | Runs Composer commands (`phpctl composer install` or `pctl composer validate`). | 13 | | `server [port] [directory]` | Runs PHP's built-in web-server (default port is `80` and default directory is current `.`). | 14 | | `sh [commands]` | Starts an interactive Shell session or runs `sh` commands. | 15 | | `repl` | Starts a PHP REPL session (powered by [PsySH](https://psysh.org/)). | 16 | | `bundle` | Bundles a project into an image and ships it as a single binary file. | 17 | 18 | ## Tools 19 | 20 | | Command | Description | 21 | |:----------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 22 | | `box` | [Box](https://github.com/box-project/box): fast, zero config application bundler with PHARs. | 23 | | `co-phpunit` | [co-phpunit](https://github.com/hyperf/testing) is a Coroutine-aware PHPUnit for testing Hyperf projects. | 24 | | `composer-require-checker` | [ComposerRequireChecker](https://github.com/maglnet/ComposerRequireChecker): A CLI tool to analyze composer dependencies and verify that no unknown symbols are used in the sources of a package. | 25 | | `couscous` | [Couscous](https://github.com/CouscousPHP/Couscous): Couscous generates a GitHub pages website from your markdown documentation. | 26 | | `deptrac` | [Deptrac](https://github.com/qossmic/deptrac): Deptrac is a static code analysis tool for PHP that helps you communicate, visualize and enforce architectural decisions in your projects. | 27 | | `exakat` | [Exakat](https://www.exakat.io) is a real time customizable static analyzer engine that analyse and fix code. | 28 | | `frankenphp` | [FrankenPHP](https://frankenphp.dev): the Modern PHP App Server, written in Go. | 29 | | `infection` | [Infection](https://infection.github.io) is a Mutation Testing Framework. | 30 | | `pest` | [Pest](https://pestphp.com) is a testing framework with a focus on simplicity. | 31 | | `php-cs-fixer` | [PHP Coding Standards Fixer (PHP CS Fixer)](https://cs.symfony.com/) fixes your code to follow standards. | 32 | | `phpcbf` | [PHP CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) is an essential development tool that ensures your code remains clean and consistent. | 33 | | `phpcs` | [PHP CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) is an essential development tool that ensures your code remains clean and consistent. | 34 | | `phpmd` | [PHP Mess Detector](https://phpmd.org/) looks for several potential problems within your source code. | 35 | | `phpstan` | [PHPStan](https://phpstan.org/) finds bugs in your code without writing tests. It's open-source and free. | 36 | | `phpunit` | [PHPUnit](https://phpunit.de) is a programmer-oriented testing framework for PHP. | 37 | | `pint` | [Pint](https://github.com/laravel/pint) is an opinionated PHP code style fixer for minimalists. | 38 | | `rector` | [Rector](https://getrector.com) is a tool that you can run on any project to get an instant upgrade or automated refactoring. | 39 | | `watchr` | [watchr](https://github.com/flavioheleno/watchr): command-line utility to explore and validate domain names and certificates. | 40 | 41 | ## Scaffolders 42 | 43 | | Command | Description | 44 | |:----------------------------|:---------------------------------------------------------------| 45 | | `create [framework] [dir]` | Creates a new project using the given framework (or package). | 46 | | `init [skeleton]` | Initializes a skeleton configuration. | 47 | 48 | ### Skeletons 49 | - `phpunit` 50 | - `php-cs-fixer` 51 | - `phpstan` 52 | - `infection` 53 | - `box` 54 | 55 | ## Helpers 56 | 57 | | Command | Description | 58 | |:-----------------|:-------------------------------------------------------------| 59 | | `help` or `man` | Displays a help message. | 60 | | `self-update` | Updates `phpctl` iself. | 61 | | `doctor` | Inspects the current `PHP_VERSION` and `PHPCTL_IMAGE`. | 62 | | `build` | Builds the current `Dockerfile` (useful for custom images). | 63 | | `images` | Shows local `phpctl` images. | 64 | -------------------------------------------------------------------------------- /docs/extensions.md: -------------------------------------------------------------------------------- 1 | --- 2 | nav_order: 5 3 | --- 4 | 5 | # Available extensions 6 |
7 | For the default Docker image we have the following modules installed (click to expand). 8 |
 9 | Core
10 | ctype
11 | curl
12 | date
13 | decimal
14 | dom
15 | ds
16 | fileinfo
17 | filter
18 | hash
19 | iconv
20 | igbinary
21 | json
22 | libxml
23 | mbstring
24 | mongodb
25 | msgpack
26 | mysqlnd
27 | openssl
28 | pcntl
29 | pcov
30 | pcre
31 | PDO
32 | pdo_mysql
33 | Phar
34 | posix
35 | random
36 | rdkafka
37 | readline
38 | redis
39 | Reflection
40 | session
41 | SimpleXML
42 | sockets
43 | sodium
44 | SPL
45 | sqlite3
46 | standard
47 | swoole
48 | tokenizer
49 | xml
50 | xmlreader
51 | xmlwriter
52 | zip
53 | zlib
54 | 
55 |
56 | 57 | You can always use your custom image with the `PHPCTL_IMAGE` variable, but feel free to ask for more essential extensions in the issues. 58 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Frictionless PHP Development 3 | nav_order: 1 4 | permalink: / 5 | --- 6 | 7 | # Frictionless PHP Development 8 | 9 | [Get started now](#getting-started){: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 } 10 | [View it on GitHub](https://github.com/opencodeco/phpctl){: .btn .fs-5 .mb-4 .mb-md-0 } 11 | 12 | Seamlessly run and switch between different versions of PHP, with different installed extensions, thanks to the power of containers. 13 | 14 | Take the advantage of goodies commands like `phpctl create` to start a new project, `phpctl repl` to start a REPL, `phpctl init` to initialize a new configuration file **and a lot more**. 15 | 16 | ## Getting started 17 | 18 | ### Installation 19 | 20 | ```shell 21 | /bin/bash -c "$(curl -fsSL https://phpctl.dev/install.sh)" 22 | ``` 23 | 24 | **That is it!** Now you have `phpctl` available in your system. 25 | 26 | #### Custom installation 27 | You can also pass an argument to install at a custom location (e.g. `~/bin`), but you have to make sure that folder is in your `$PATH` variable. 28 | ```shell 29 | /bin/bash -c "$(curl -fsSL https://phpctl.dev/install.sh)" ~/bin 30 | ``` 31 | 32 | #### Homebrew 33 | ```shell 34 | brew install opencodeco/phpctl/phpctl 35 | ``` 36 | 37 | Or add the `oppencodeco` tap with `brew tap opencodeco/phpctl` and then `brew install phpctl`. 38 | 39 | ### Update 40 | You can re-run the installer or use the `self-update` command: 41 | ```shell 42 | phpctl self-update 43 | ``` 44 | 45 | For those using Homebrew `brew upgrade opencodeco/phpctl/phpctl` or when run `brew update`. 46 | 47 | ### Usage 48 | 49 | Simple as calling any other command in your terminal: 50 | 51 | ```shell 52 | phpctl [options] 53 | ``` 54 | 55 | You will also have aliases for the most common commands available without the `phpctl` prefix, like: 56 | - `php` 57 | - `composer` 58 | - `phpunit` 59 | - `php-cs-fixer` 60 | - etc 61 | 62 | So you can use them as you would normally do: 63 | 64 | ```shell 65 | php -v # same as `phpctl php -v` 66 | ``` 67 | 68 | Or 69 | 70 | ```shell 71 | composer --version # same as `phpctl composer --version` 72 | ``` 73 | 74 | **Have fun!** Feel free to open any issues or PRs. -------------------------------------------------------------------------------- /docs/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | INSTALL_DIR=~/.phpctl 4 | if [ -z "$1" ]; then 5 | SUDO=sudo 6 | SYMLINK_DIR=/usr/local/bin 7 | else 8 | SUDO="" 9 | SYMLINK_DIR=$1 10 | fi 11 | 12 | echo -e "\033[0;33mInstalling phpctl at \033[0m$INSTALL_DIR" 13 | if [ -d "$INSTALL_DIR" ]; then 14 | echo "The install directory is not empty. Attempting to remove it..." 15 | rm -rf $INSTALL_DIR 16 | fi 17 | 18 | echo -n "" 19 | git clone --quiet https://github.com/opencodeco/phpctl.git $INSTALL_DIR & 20 | PID=$! 21 | while kill -0 $PID 2> /dev/null; do 22 | for CHAR in '-' '/' '|' '\'; do 23 | printf "\b$CHAR" 24 | sleep 0.1 25 | done 26 | done 27 | printf "\r" 28 | 29 | 30 | if [ -z "$1" ]; then 31 | echo -n "Sudo will be prompted to symlink the phpctl files." 32 | else 33 | echo -n "Files will be symlinked to ${SYMLINK_DIR}." 34 | fi 35 | echo -e -n " \033[0;32mDo you want to continue? (Y/n)\033[0m " 36 | read -r answer 37 | if [ "$answer" != "${answer#[Nn]}" ]; then 38 | echo -e "\033[0;31mTo use phpctl globally, link the cloned script to your bin directory, like:\033[0m" 39 | echo "" 40 | for file in "${INSTALL_DIR}"/bin/*; do 41 | bin=$(basename "$file") 42 | echo " ${SUDO} ln -sf ${INSTALL_DIR}/bin/$bin ${SYMLINK_DIR}/$bin" 43 | done 44 | else 45 | $SUDO ${INSTALL_DIR}/scripts/symlink-bins.sh ${INSTALL_DIR} 46 | fi 47 | -------------------------------------------------------------------------------- /docs/phpctlini.md: -------------------------------------------------------------------------------- 1 | --- 2 | nav_order: 4 3 | --- 4 | 5 | # The `phpctl.ini` file 6 | You can also add a `phpctl.ini` file at project's root directory to set any [`php.ini` directive](https://www.php.net/manual/en/ini.list.php). 7 | ```ini 8 | memory_limit = 1337M 9 | ``` 10 | 11 | ```shell 12 | $ phpctl php -i | grep memory_limit 13 | memory_limit => 1337M => 1337M 14 | ``` 15 | -------------------------------------------------------------------------------- /docs/phpctlrc.md: -------------------------------------------------------------------------------- 1 | --- 2 | nav_order: 3 3 | --- 4 | 5 | # The `.phpctlrc` file 6 | You can also add a `.phpctlrc` file at project's root directory with some overrides like: 7 | 8 | ## Environment variables 9 | 10 | | Variable | Description | 11 | |:----------------|:-----------------------------------| 12 | | `PHP_VERSION` | Values can be `82` and `83` | 13 | | `PHPCTL_IMAGE` | Use to name your own custom image | 14 | 15 | For example: 16 | ```shell 17 | PHP_VERSION=83 18 | ``` 19 | 20 | ## Docker behaviour 21 | 22 | ### Run options 23 | 24 | You can also provide any additional [Docker `run` arguments](https://docs.docker.com/engine/reference/commandline/run/#options) using the `args` variable. 25 | 26 | For example, suppose you want to bind the `9501` port from the running `phpctl` container to your host, 27 | you can add the following to your `.phpctlrc` file: 28 | ```shell 29 | args=(-p 9501:9501) 30 | ``` 31 | 32 | ### Build options 33 | 34 | You can also provide [build options](https://docs.docker.com/engine/reference/commandline/build/) to the build command using the `build` variable: 35 | ```shell 36 | build=(--build-arg APP_ENV=dev --label phprocks) 37 | ``` 38 | 39 | ## Podman 40 | 41 | You can use Podman instead of Docker by setting the `PHPCTL_RUNTIME` variable to `podman` in your environment variables or at `.phpctlrc` file. 42 | ```shell 43 | PHPCTL_RUNTIME=podman phpctl php -v 44 | ``` 45 | 46 | ## Host user 47 | 48 | By default, `phpctl` creates an user considering host user. You can change from `root` to host user through `PHPCTL_USER` variable. 49 | ```shell 50 | PHPCTL_USER=your_user phpctl sh whoami 51 | ``` 52 | -------------------------------------------------------------------------------- /docs/uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | INSTALL_DIR=~/.phpctl 4 | SYMLINK_DIR=/usr/local/bin 5 | 6 | LINKS=( 7 | composer 8 | composer-require-checker 9 | co-phpunit 10 | couscous 11 | deptrac 12 | exakat 13 | frankenphp 14 | infection 15 | notty 16 | pest 17 | php 18 | phpcbf 19 | phpcs 20 | php-cs-fixer 21 | phpctl 22 | phpmd 23 | phpstan 24 | phpunit 25 | pint 26 | rector 27 | watchr 28 | ) 29 | 30 | # Removing symlink 31 | echo "Removing symbolic links..." 32 | for link in "${LINKS[@]}"; do 33 | if [ -L "${SYMLINK_DIR}/${link}" ]; then 34 | sudo rm "${SYMLINK_DIR}/${link}" 35 | echo "Removed ${SYMLINK_DIR}/${link}" 36 | else 37 | echo "Link ${SYMLINK_DIR}/${link} does not exist, skipping." 38 | fi 39 | done 40 | 41 | # Opcional: removing directory 42 | echo -e "\nDo you want to remove the installation directory (${INSTALL_DIR})? (Y/n) " 43 | read -r answer 44 | if [ "$answer" != "${answer#[Yy]}" ]; then 45 | rm -rf "$INSTALL_DIR" 46 | echo "Removed installation directory: ${INSTALL_DIR}" 47 | else 48 | echo "Skipping removal of installation directory." 49 | fi 50 | 51 | echo "Uninstallation complete." -------------------------------------------------------------------------------- /docs/why.md: -------------------------------------------------------------------------------- 1 | --- 2 | nav_order: 6 3 | --- 4 | 5 | # Why it exists? 6 | 7 | After some years struggling with different PHP distributions into different operating systems, dealing with different PHP versions and sets of extensions, I came out with `phpctl` to use the power of containers to seamlessly run PHP for development environments. 8 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | Welcome to the `phpctl` examples page. 4 | 5 | Feel free to pick one to see how it is done: 6 | 7 | - [box](box) 8 | - [bundle](bundle) 9 | - [frakenphp](frankenphp) 10 | - [pest](pest) 11 | - [server](server) 12 | -------------------------------------------------------------------------------- /examples/box/.gitignore: -------------------------------------------------------------------------------- 1 | main.phar 2 | vendor/ 3 | -------------------------------------------------------------------------------- /examples/box/Makefile: -------------------------------------------------------------------------------- 1 | default: main.phar 2 | 3 | vendor/autoload.php: composer.json 4 | phpctl composer install 5 | 6 | main.phar: vendor/autoload.php 7 | phpctl box compile 8 | 9 | clean: 10 | @rm -rf main.phar 11 | -------------------------------------------------------------------------------- /examples/box/README.md: -------------------------------------------------------------------------------- 1 | # Box 2 | 3 | To use `box` with `phpctl` you can simply `phpctl box` like: 4 | ```shell 5 | phpctl box compile 6 | ``` 7 | 8 | You can also use `init` to initialize a configuration file: 9 | ```shell 10 | phpctl init box 11 | ``` 12 | 13 | For this example, we already have a `Makefile` configured so just: 14 | ```shell 15 | make 16 | ``` 17 | 18 | Then a `main.phar` will be generated: 19 | ```shell 20 | ./main.phar test 21 | ``` 22 | 23 | Head to the [Box project documentation](https://box-project.github.io/box/configuration/) to see the full and in details what you can do. 24 | 25 | > [!NOTE] 26 | > This example is using [minicli](https://docs.minicli.dev/en/latest/) for demonstration purposes. 27 | -------------------------------------------------------------------------------- /examples/box/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "phpctl/examples", 3 | "description": "Example on using box with phpctl", 4 | "type": "project", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "leocavalcante", 9 | "email": "lc@leocavalcante.com" 10 | } 11 | ], 12 | "minimum-stability": "stable", 13 | "bin": ["main"], 14 | "require": { 15 | "minicli/minicli": "^4.2" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/box/composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "8c29a580845cfe8ac98268cb12caf54d", 8 | "packages": [ 9 | { 10 | "name": "minicli/minicli", 11 | "version": "4.2.0", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/minicli/minicli.git", 15 | "reference": "1675c0609205c106bb7c2353888dec361808d92e" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/minicli/minicli/zipball/1675c0609205c106bb7c2353888dec361808d92e", 20 | "reference": "1675c0609205c106bb7c2353888dec361808d92e", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "ext-readline": "*", 25 | "php": ">=8.1" 26 | }, 27 | "require-dev": { 28 | "laravel/pint": "^1.10", 29 | "mockery/mockery": "^1.5", 30 | "pestphp/pest": "^2.5", 31 | "phpstan/phpstan": "^1.10" 32 | }, 33 | "type": "library", 34 | "autoload": { 35 | "files": [ 36 | "src/helpers.php" 37 | ], 38 | "psr-4": { 39 | "Minicli\\": "src/" 40 | } 41 | }, 42 | "notification-url": "https://packagist.org/downloads/", 43 | "license": [ 44 | "MIT" 45 | ], 46 | "description": "Experimental micro CLI framework for PHP", 47 | "homepage": "https://github.com/minicli/minicli", 48 | "keywords": [ 49 | "cli", 50 | "command-line" 51 | ], 52 | "support": { 53 | "issues": "https://github.com/minicli/minicli/issues", 54 | "source": "https://github.com/minicli/minicli/tree/4.2.0" 55 | }, 56 | "funding": [ 57 | { 58 | "url": "https://github.com/erikaheidi", 59 | "type": "github" 60 | } 61 | ], 62 | "time": "2023-06-27T08:16:45+00:00" 63 | } 64 | ], 65 | "packages-dev": [], 66 | "aliases": [], 67 | "minimum-stability": "stable", 68 | "stability-flags": [], 69 | "prefer-stable": false, 70 | "prefer-lowest": false, 71 | "platform": [], 72 | "platform-dev": [], 73 | "plugin-api-version": "2.6.0" 74 | } 75 | -------------------------------------------------------------------------------- /examples/box/main: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | [ 14 | __DIR__ . '/app/Command', 15 | ], 16 | 'theme' => '\Unicorn', 17 | 'debug' => false, 18 | ]); 19 | 20 | $app->registerCommand('test', function () use ($app) { 21 | $app->success('Hello World!' , false); 22 | $app->info('With Background!' , true); 23 | $app->error('Quitting!', false); 24 | }); 25 | 26 | $app->runCommand($argv); 27 | -------------------------------------------------------------------------------- /examples/bundle/.gitignore: -------------------------------------------------------------------------------- 1 | phpctl-bundle 2 | -------------------------------------------------------------------------------- /examples/bundle/Makefile: -------------------------------------------------------------------------------- 1 | IMAGE=docker.io/opencodeco/phpctl-bundle-example 2 | 3 | phpctl-bundle: clean 4 | phpctl bundle $(IMAGE) phpctl-bundle main.php 5 | 6 | .PHONY: push 7 | push: 8 | docker push $(IMAGE) 9 | 10 | install: 11 | mv phpctl-bundle /usr/local/bin 12 | 13 | clean: 14 | rm -rf phpctl-bundle 15 | -------------------------------------------------------------------------------- /examples/bundle/README.md: -------------------------------------------------------------------------------- 1 | # Bundle 2 | 3 | This is the example directory for the `bundle` command. 4 | 5 | This command is used to bundle a project into an image and ship it as a single binanry file. 6 | 7 | The command usage is based on `phpctl bundle [image] [alias] [entryfile]`. 8 | 9 | But this directory uses `make` to make life easier. 10 | 11 | So just: 12 | ```shell 13 | make && make install 14 | ``` 15 | 16 | Then execute: 17 | ```shell 18 | phpctl-bundle 19 | ``` 20 | 21 | You should see: 22 | ```text 23 | Hello, World! 24 | ``` 25 | As the output. 26 | 27 | The program is `main.php`: 28 | ```php 29 | 2 | 7 | 8 | 9 | ./tests 10 | 11 | 12 | 13 | 14 | ./app 15 | ./src 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/pest/tests/Feature/ExampleTest.php: -------------------------------------------------------------------------------- 1 | toBeTrue(); 5 | }); 6 | -------------------------------------------------------------------------------- /examples/pest/tests/Pest.php: -------------------------------------------------------------------------------- 1 | in('Feature'); 15 | 16 | /* 17 | |-------------------------------------------------------------------------- 18 | | Expectations 19 | |-------------------------------------------------------------------------- 20 | | 21 | | When you're writing tests, you often need to check that values meet certain conditions. The 22 | | "expect()" function gives you access to a set of "expectations" methods that you can use 23 | | to assert different things. Of course, you may extend the Expectation API at any time. 24 | | 25 | */ 26 | 27 | expect()->extend('toBeOne', function () { 28 | return $this->toBe(1); 29 | }); 30 | 31 | /* 32 | |-------------------------------------------------------------------------- 33 | | Functions 34 | |-------------------------------------------------------------------------- 35 | | 36 | | While Pest is very powerful out-of-the-box, you may have some testing code specific to your 37 | | project that you don't want to repeat in every file. Here you can also expose helpers as 38 | | global functions to help you to reduce the number of lines of code in your test files. 39 | | 40 | */ 41 | 42 | function something() 43 | { 44 | // .. 45 | } 46 | -------------------------------------------------------------------------------- /examples/pest/tests/TestCase.php: -------------------------------------------------------------------------------- 1 | toBeTrue(); 5 | }); 6 | -------------------------------------------------------------------------------- /examples/phpctl.ini/phpctl.ini: -------------------------------------------------------------------------------- 1 | memory_limit = 1337M 2 | -------------------------------------------------------------------------------- /examples/phpctlrc/.phpctlrc: -------------------------------------------------------------------------------- 1 | PHPCTL_IMAGE=foo 2 | -------------------------------------------------------------------------------- /examples/phpmd/.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | -------------------------------------------------------------------------------- /examples/phpmd/README.md: -------------------------------------------------------------------------------- 1 | # PHP Mess Detector 2 | 3 | An example of [PHP Mess Detector](https://phpmd.org/) usage. 4 | 5 | Run `phpctl phpmd src text cleancode,controversial,design,naming,unusedcode` to get PHPMD output execution for [Example](./src/Example.php) class. 6 | 7 | You should have an output as following: 8 | ```shell 9 | /usr/local/src/src/Example.php:6 LongVariable Avoid excessively long variable names like $thiIsAnAmazingVariable. Keep variable name length under 20. 10 | /usr/local/src/src/Example.php:8 UnusedLocalVariable Avoid unused local variables such as '$anotherVariable'. 11 | /usr/local/src/src/Example.php:11 CamelCaseMethodName The method snake_case_method is not named in camelCase. 12 | /usr/local/src/src/Example.php:17 MissingImport Missing class import via use statement (line '17', column '23'). 13 | /usr/local/src/src/Example.php:18 EmptyCatchBlock Avoid using empty try-catch blocks in uselessCatchBlock. 14 | /usr/local/src/src/Example.php:24 UndefinedVariable Avoid using undefined variables such as '$age' which will lead to PHP notices. 15 | /usr/local/src/src/Example.php:24 UnusedLocalVariable Avoid unused local variables such as '$age'. 16 | ``` -------------------------------------------------------------------------------- /examples/phpmd/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "autoload": { 3 | "psr-4": { 4 | "App\\": "src/" 5 | } 6 | }, 7 | "require-dev": { 8 | "phpmd/phpmd": "^2.15" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/phpmd/composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "ba732fb5b882b63abfb5116571fdf5b7", 8 | "packages": [], 9 | "packages-dev": [ 10 | { 11 | "name": "composer/pcre", 12 | "version": "3.1.1", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/composer/pcre.git", 16 | "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/composer/pcre/zipball/00104306927c7a0919b4ced2aaa6782c1e61a3c9", 21 | "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "php": "^7.4 || ^8.0" 26 | }, 27 | "require-dev": { 28 | "phpstan/phpstan": "^1.3", 29 | "phpstan/phpstan-strict-rules": "^1.1", 30 | "symfony/phpunit-bridge": "^5" 31 | }, 32 | "type": "library", 33 | "extra": { 34 | "branch-alias": { 35 | "dev-main": "3.x-dev" 36 | } 37 | }, 38 | "autoload": { 39 | "psr-4": { 40 | "Composer\\Pcre\\": "src" 41 | } 42 | }, 43 | "notification-url": "https://packagist.org/downloads/", 44 | "license": [ 45 | "MIT" 46 | ], 47 | "authors": [ 48 | { 49 | "name": "Jordi Boggiano", 50 | "email": "j.boggiano@seld.be", 51 | "homepage": "http://seld.be" 52 | } 53 | ], 54 | "description": "PCRE wrapping library that offers type-safe preg_* replacements.", 55 | "keywords": [ 56 | "PCRE", 57 | "preg", 58 | "regex", 59 | "regular expression" 60 | ], 61 | "support": { 62 | "issues": "https://github.com/composer/pcre/issues", 63 | "source": "https://github.com/composer/pcre/tree/3.1.1" 64 | }, 65 | "funding": [ 66 | { 67 | "url": "https://packagist.com", 68 | "type": "custom" 69 | }, 70 | { 71 | "url": "https://github.com/composer", 72 | "type": "github" 73 | }, 74 | { 75 | "url": "https://tidelift.com/funding/github/packagist/composer/composer", 76 | "type": "tidelift" 77 | } 78 | ], 79 | "time": "2023-10-11T07:11:09+00:00" 80 | }, 81 | { 82 | "name": "composer/xdebug-handler", 83 | "version": "3.0.3", 84 | "source": { 85 | "type": "git", 86 | "url": "https://github.com/composer/xdebug-handler.git", 87 | "reference": "ced299686f41dce890debac69273b47ffe98a40c" 88 | }, 89 | "dist": { 90 | "type": "zip", 91 | "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ced299686f41dce890debac69273b47ffe98a40c", 92 | "reference": "ced299686f41dce890debac69273b47ffe98a40c", 93 | "shasum": "" 94 | }, 95 | "require": { 96 | "composer/pcre": "^1 || ^2 || ^3", 97 | "php": "^7.2.5 || ^8.0", 98 | "psr/log": "^1 || ^2 || ^3" 99 | }, 100 | "require-dev": { 101 | "phpstan/phpstan": "^1.0", 102 | "phpstan/phpstan-strict-rules": "^1.1", 103 | "symfony/phpunit-bridge": "^6.0" 104 | }, 105 | "type": "library", 106 | "autoload": { 107 | "psr-4": { 108 | "Composer\\XdebugHandler\\": "src" 109 | } 110 | }, 111 | "notification-url": "https://packagist.org/downloads/", 112 | "license": [ 113 | "MIT" 114 | ], 115 | "authors": [ 116 | { 117 | "name": "John Stevenson", 118 | "email": "john-stevenson@blueyonder.co.uk" 119 | } 120 | ], 121 | "description": "Restarts a process without Xdebug.", 122 | "keywords": [ 123 | "Xdebug", 124 | "performance" 125 | ], 126 | "support": { 127 | "irc": "irc://irc.freenode.org/composer", 128 | "issues": "https://github.com/composer/xdebug-handler/issues", 129 | "source": "https://github.com/composer/xdebug-handler/tree/3.0.3" 130 | }, 131 | "funding": [ 132 | { 133 | "url": "https://packagist.com", 134 | "type": "custom" 135 | }, 136 | { 137 | "url": "https://github.com/composer", 138 | "type": "github" 139 | }, 140 | { 141 | "url": "https://tidelift.com/funding/github/packagist/composer/composer", 142 | "type": "tidelift" 143 | } 144 | ], 145 | "time": "2022-02-25T21:32:43+00:00" 146 | }, 147 | { 148 | "name": "pdepend/pdepend", 149 | "version": "2.16.2", 150 | "source": { 151 | "type": "git", 152 | "url": "https://github.com/pdepend/pdepend.git", 153 | "reference": "f942b208dc2a0868454d01b29f0c75bbcfc6ed58" 154 | }, 155 | "dist": { 156 | "type": "zip", 157 | "url": "https://api.github.com/repos/pdepend/pdepend/zipball/f942b208dc2a0868454d01b29f0c75bbcfc6ed58", 158 | "reference": "f942b208dc2a0868454d01b29f0c75bbcfc6ed58", 159 | "shasum": "" 160 | }, 161 | "require": { 162 | "php": ">=5.3.7", 163 | "symfony/config": "^2.3.0|^3|^4|^5|^6.0|^7.0", 164 | "symfony/dependency-injection": "^2.3.0|^3|^4|^5|^6.0|^7.0", 165 | "symfony/filesystem": "^2.3.0|^3|^4|^5|^6.0|^7.0", 166 | "symfony/polyfill-mbstring": "^1.19" 167 | }, 168 | "require-dev": { 169 | "easy-doc/easy-doc": "0.0.0|^1.2.3", 170 | "gregwar/rst": "^1.0", 171 | "squizlabs/php_codesniffer": "^2.0.0" 172 | }, 173 | "bin": [ 174 | "src/bin/pdepend" 175 | ], 176 | "type": "library", 177 | "extra": { 178 | "branch-alias": { 179 | "dev-master": "2.x-dev" 180 | } 181 | }, 182 | "autoload": { 183 | "psr-4": { 184 | "PDepend\\": "src/main/php/PDepend" 185 | } 186 | }, 187 | "notification-url": "https://packagist.org/downloads/", 188 | "license": [ 189 | "BSD-3-Clause" 190 | ], 191 | "description": "Official version of pdepend to be handled with Composer", 192 | "keywords": [ 193 | "PHP Depend", 194 | "PHP_Depend", 195 | "dev", 196 | "pdepend" 197 | ], 198 | "support": { 199 | "issues": "https://github.com/pdepend/pdepend/issues", 200 | "source": "https://github.com/pdepend/pdepend/tree/2.16.2" 201 | }, 202 | "funding": [ 203 | { 204 | "url": "https://tidelift.com/funding/github/packagist/pdepend/pdepend", 205 | "type": "tidelift" 206 | } 207 | ], 208 | "time": "2023-12-17T18:09:59+00:00" 209 | }, 210 | { 211 | "name": "phpmd/phpmd", 212 | "version": "2.15.0", 213 | "source": { 214 | "type": "git", 215 | "url": "https://github.com/phpmd/phpmd.git", 216 | "reference": "74a1f56e33afad4128b886e334093e98e1b5e7c0" 217 | }, 218 | "dist": { 219 | "type": "zip", 220 | "url": "https://api.github.com/repos/phpmd/phpmd/zipball/74a1f56e33afad4128b886e334093e98e1b5e7c0", 221 | "reference": "74a1f56e33afad4128b886e334093e98e1b5e7c0", 222 | "shasum": "" 223 | }, 224 | "require": { 225 | "composer/xdebug-handler": "^1.0 || ^2.0 || ^3.0", 226 | "ext-xml": "*", 227 | "pdepend/pdepend": "^2.16.1", 228 | "php": ">=5.3.9" 229 | }, 230 | "require-dev": { 231 | "easy-doc/easy-doc": "0.0.0 || ^1.3.2", 232 | "ext-json": "*", 233 | "ext-simplexml": "*", 234 | "gregwar/rst": "^1.0", 235 | "mikey179/vfsstream": "^1.6.8", 236 | "squizlabs/php_codesniffer": "^2.9.2 || ^3.7.2" 237 | }, 238 | "bin": [ 239 | "src/bin/phpmd" 240 | ], 241 | "type": "library", 242 | "autoload": { 243 | "psr-0": { 244 | "PHPMD\\": "src/main/php" 245 | } 246 | }, 247 | "notification-url": "https://packagist.org/downloads/", 248 | "license": [ 249 | "BSD-3-Clause" 250 | ], 251 | "authors": [ 252 | { 253 | "name": "Manuel Pichler", 254 | "email": "github@manuel-pichler.de", 255 | "homepage": "https://github.com/manuelpichler", 256 | "role": "Project Founder" 257 | }, 258 | { 259 | "name": "Marc Würth", 260 | "email": "ravage@bluewin.ch", 261 | "homepage": "https://github.com/ravage84", 262 | "role": "Project Maintainer" 263 | }, 264 | { 265 | "name": "Other contributors", 266 | "homepage": "https://github.com/phpmd/phpmd/graphs/contributors", 267 | "role": "Contributors" 268 | } 269 | ], 270 | "description": "PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD.", 271 | "homepage": "https://phpmd.org/", 272 | "keywords": [ 273 | "dev", 274 | "mess detection", 275 | "mess detector", 276 | "pdepend", 277 | "phpmd", 278 | "pmd" 279 | ], 280 | "support": { 281 | "irc": "irc://irc.freenode.org/phpmd", 282 | "issues": "https://github.com/phpmd/phpmd/issues", 283 | "source": "https://github.com/phpmd/phpmd/tree/2.15.0" 284 | }, 285 | "funding": [ 286 | { 287 | "url": "https://tidelift.com/funding/github/packagist/phpmd/phpmd", 288 | "type": "tidelift" 289 | } 290 | ], 291 | "time": "2023-12-11T08:22:20+00:00" 292 | }, 293 | { 294 | "name": "psr/container", 295 | "version": "2.0.2", 296 | "source": { 297 | "type": "git", 298 | "url": "https://github.com/php-fig/container.git", 299 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" 300 | }, 301 | "dist": { 302 | "type": "zip", 303 | "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", 304 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", 305 | "shasum": "" 306 | }, 307 | "require": { 308 | "php": ">=7.4.0" 309 | }, 310 | "type": "library", 311 | "extra": { 312 | "branch-alias": { 313 | "dev-master": "2.0.x-dev" 314 | } 315 | }, 316 | "autoload": { 317 | "psr-4": { 318 | "Psr\\Container\\": "src/" 319 | } 320 | }, 321 | "notification-url": "https://packagist.org/downloads/", 322 | "license": [ 323 | "MIT" 324 | ], 325 | "authors": [ 326 | { 327 | "name": "PHP-FIG", 328 | "homepage": "https://www.php-fig.org/" 329 | } 330 | ], 331 | "description": "Common Container Interface (PHP FIG PSR-11)", 332 | "homepage": "https://github.com/php-fig/container", 333 | "keywords": [ 334 | "PSR-11", 335 | "container", 336 | "container-interface", 337 | "container-interop", 338 | "psr" 339 | ], 340 | "support": { 341 | "issues": "https://github.com/php-fig/container/issues", 342 | "source": "https://github.com/php-fig/container/tree/2.0.2" 343 | }, 344 | "time": "2021-11-05T16:47:00+00:00" 345 | }, 346 | { 347 | "name": "psr/log", 348 | "version": "3.0.0", 349 | "source": { 350 | "type": "git", 351 | "url": "https://github.com/php-fig/log.git", 352 | "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" 353 | }, 354 | "dist": { 355 | "type": "zip", 356 | "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", 357 | "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", 358 | "shasum": "" 359 | }, 360 | "require": { 361 | "php": ">=8.0.0" 362 | }, 363 | "type": "library", 364 | "extra": { 365 | "branch-alias": { 366 | "dev-master": "3.x-dev" 367 | } 368 | }, 369 | "autoload": { 370 | "psr-4": { 371 | "Psr\\Log\\": "src" 372 | } 373 | }, 374 | "notification-url": "https://packagist.org/downloads/", 375 | "license": [ 376 | "MIT" 377 | ], 378 | "authors": [ 379 | { 380 | "name": "PHP-FIG", 381 | "homepage": "https://www.php-fig.org/" 382 | } 383 | ], 384 | "description": "Common interface for logging libraries", 385 | "homepage": "https://github.com/php-fig/log", 386 | "keywords": [ 387 | "log", 388 | "psr", 389 | "psr-3" 390 | ], 391 | "support": { 392 | "source": "https://github.com/php-fig/log/tree/3.0.0" 393 | }, 394 | "time": "2021-07-14T16:46:02+00:00" 395 | }, 396 | { 397 | "name": "symfony/config", 398 | "version": "v7.0.3", 399 | "source": { 400 | "type": "git", 401 | "url": "https://github.com/symfony/config.git", 402 | "reference": "86a5027869ca3d6bdecae6d5d6c2f77c8f2c1d16" 403 | }, 404 | "dist": { 405 | "type": "zip", 406 | "url": "https://api.github.com/repos/symfony/config/zipball/86a5027869ca3d6bdecae6d5d6c2f77c8f2c1d16", 407 | "reference": "86a5027869ca3d6bdecae6d5d6c2f77c8f2c1d16", 408 | "shasum": "" 409 | }, 410 | "require": { 411 | "php": ">=8.2", 412 | "symfony/deprecation-contracts": "^2.5|^3", 413 | "symfony/filesystem": "^6.4|^7.0", 414 | "symfony/polyfill-ctype": "~1.8" 415 | }, 416 | "conflict": { 417 | "symfony/finder": "<6.4", 418 | "symfony/service-contracts": "<2.5" 419 | }, 420 | "require-dev": { 421 | "symfony/event-dispatcher": "^6.4|^7.0", 422 | "symfony/finder": "^6.4|^7.0", 423 | "symfony/messenger": "^6.4|^7.0", 424 | "symfony/service-contracts": "^2.5|^3", 425 | "symfony/yaml": "^6.4|^7.0" 426 | }, 427 | "type": "library", 428 | "autoload": { 429 | "psr-4": { 430 | "Symfony\\Component\\Config\\": "" 431 | }, 432 | "exclude-from-classmap": [ 433 | "/Tests/" 434 | ] 435 | }, 436 | "notification-url": "https://packagist.org/downloads/", 437 | "license": [ 438 | "MIT" 439 | ], 440 | "authors": [ 441 | { 442 | "name": "Fabien Potencier", 443 | "email": "fabien@symfony.com" 444 | }, 445 | { 446 | "name": "Symfony Community", 447 | "homepage": "https://symfony.com/contributors" 448 | } 449 | ], 450 | "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", 451 | "homepage": "https://symfony.com", 452 | "support": { 453 | "source": "https://github.com/symfony/config/tree/v7.0.3" 454 | }, 455 | "funding": [ 456 | { 457 | "url": "https://symfony.com/sponsor", 458 | "type": "custom" 459 | }, 460 | { 461 | "url": "https://github.com/fabpot", 462 | "type": "github" 463 | }, 464 | { 465 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 466 | "type": "tidelift" 467 | } 468 | ], 469 | "time": "2024-01-30T08:34:29+00:00" 470 | }, 471 | { 472 | "name": "symfony/dependency-injection", 473 | "version": "v7.0.3", 474 | "source": { 475 | "type": "git", 476 | "url": "https://github.com/symfony/dependency-injection.git", 477 | "reference": "e915c6684b8e3ae90a4441f6823ebbb40edf0b92" 478 | }, 479 | "dist": { 480 | "type": "zip", 481 | "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/e915c6684b8e3ae90a4441f6823ebbb40edf0b92", 482 | "reference": "e915c6684b8e3ae90a4441f6823ebbb40edf0b92", 483 | "shasum": "" 484 | }, 485 | "require": { 486 | "php": ">=8.2", 487 | "psr/container": "^1.1|^2.0", 488 | "symfony/deprecation-contracts": "^2.5|^3", 489 | "symfony/service-contracts": "^3.3", 490 | "symfony/var-exporter": "^6.4|^7.0" 491 | }, 492 | "conflict": { 493 | "ext-psr": "<1.1|>=2", 494 | "symfony/config": "<6.4", 495 | "symfony/finder": "<6.4", 496 | "symfony/yaml": "<6.4" 497 | }, 498 | "provide": { 499 | "psr/container-implementation": "1.1|2.0", 500 | "symfony/service-implementation": "1.1|2.0|3.0" 501 | }, 502 | "require-dev": { 503 | "symfony/config": "^6.4|^7.0", 504 | "symfony/expression-language": "^6.4|^7.0", 505 | "symfony/yaml": "^6.4|^7.0" 506 | }, 507 | "type": "library", 508 | "autoload": { 509 | "psr-4": { 510 | "Symfony\\Component\\DependencyInjection\\": "" 511 | }, 512 | "exclude-from-classmap": [ 513 | "/Tests/" 514 | ] 515 | }, 516 | "notification-url": "https://packagist.org/downloads/", 517 | "license": [ 518 | "MIT" 519 | ], 520 | "authors": [ 521 | { 522 | "name": "Fabien Potencier", 523 | "email": "fabien@symfony.com" 524 | }, 525 | { 526 | "name": "Symfony Community", 527 | "homepage": "https://symfony.com/contributors" 528 | } 529 | ], 530 | "description": "Allows you to standardize and centralize the way objects are constructed in your application", 531 | "homepage": "https://symfony.com", 532 | "support": { 533 | "source": "https://github.com/symfony/dependency-injection/tree/v7.0.3" 534 | }, 535 | "funding": [ 536 | { 537 | "url": "https://symfony.com/sponsor", 538 | "type": "custom" 539 | }, 540 | { 541 | "url": "https://github.com/fabpot", 542 | "type": "github" 543 | }, 544 | { 545 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 546 | "type": "tidelift" 547 | } 548 | ], 549 | "time": "2024-01-30T08:34:29+00:00" 550 | }, 551 | { 552 | "name": "symfony/deprecation-contracts", 553 | "version": "v3.4.0", 554 | "source": { 555 | "type": "git", 556 | "url": "https://github.com/symfony/deprecation-contracts.git", 557 | "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" 558 | }, 559 | "dist": { 560 | "type": "zip", 561 | "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", 562 | "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", 563 | "shasum": "" 564 | }, 565 | "require": { 566 | "php": ">=8.1" 567 | }, 568 | "type": "library", 569 | "extra": { 570 | "branch-alias": { 571 | "dev-main": "3.4-dev" 572 | }, 573 | "thanks": { 574 | "name": "symfony/contracts", 575 | "url": "https://github.com/symfony/contracts" 576 | } 577 | }, 578 | "autoload": { 579 | "files": [ 580 | "function.php" 581 | ] 582 | }, 583 | "notification-url": "https://packagist.org/downloads/", 584 | "license": [ 585 | "MIT" 586 | ], 587 | "authors": [ 588 | { 589 | "name": "Nicolas Grekas", 590 | "email": "p@tchwork.com" 591 | }, 592 | { 593 | "name": "Symfony Community", 594 | "homepage": "https://symfony.com/contributors" 595 | } 596 | ], 597 | "description": "A generic function and convention to trigger deprecation notices", 598 | "homepage": "https://symfony.com", 599 | "support": { 600 | "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0" 601 | }, 602 | "funding": [ 603 | { 604 | "url": "https://symfony.com/sponsor", 605 | "type": "custom" 606 | }, 607 | { 608 | "url": "https://github.com/fabpot", 609 | "type": "github" 610 | }, 611 | { 612 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 613 | "type": "tidelift" 614 | } 615 | ], 616 | "time": "2023-05-23T14:45:45+00:00" 617 | }, 618 | { 619 | "name": "symfony/filesystem", 620 | "version": "v7.0.3", 621 | "source": { 622 | "type": "git", 623 | "url": "https://github.com/symfony/filesystem.git", 624 | "reference": "2890e3a825bc0c0558526c04499c13f83e1b6b12" 625 | }, 626 | "dist": { 627 | "type": "zip", 628 | "url": "https://api.github.com/repos/symfony/filesystem/zipball/2890e3a825bc0c0558526c04499c13f83e1b6b12", 629 | "reference": "2890e3a825bc0c0558526c04499c13f83e1b6b12", 630 | "shasum": "" 631 | }, 632 | "require": { 633 | "php": ">=8.2", 634 | "symfony/polyfill-ctype": "~1.8", 635 | "symfony/polyfill-mbstring": "~1.8" 636 | }, 637 | "type": "library", 638 | "autoload": { 639 | "psr-4": { 640 | "Symfony\\Component\\Filesystem\\": "" 641 | }, 642 | "exclude-from-classmap": [ 643 | "/Tests/" 644 | ] 645 | }, 646 | "notification-url": "https://packagist.org/downloads/", 647 | "license": [ 648 | "MIT" 649 | ], 650 | "authors": [ 651 | { 652 | "name": "Fabien Potencier", 653 | "email": "fabien@symfony.com" 654 | }, 655 | { 656 | "name": "Symfony Community", 657 | "homepage": "https://symfony.com/contributors" 658 | } 659 | ], 660 | "description": "Provides basic utilities for the filesystem", 661 | "homepage": "https://symfony.com", 662 | "support": { 663 | "source": "https://github.com/symfony/filesystem/tree/v7.0.3" 664 | }, 665 | "funding": [ 666 | { 667 | "url": "https://symfony.com/sponsor", 668 | "type": "custom" 669 | }, 670 | { 671 | "url": "https://github.com/fabpot", 672 | "type": "github" 673 | }, 674 | { 675 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 676 | "type": "tidelift" 677 | } 678 | ], 679 | "time": "2024-01-23T15:02:46+00:00" 680 | }, 681 | { 682 | "name": "symfony/polyfill-ctype", 683 | "version": "v1.29.0", 684 | "source": { 685 | "type": "git", 686 | "url": "https://github.com/symfony/polyfill-ctype.git", 687 | "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4" 688 | }, 689 | "dist": { 690 | "type": "zip", 691 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4", 692 | "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4", 693 | "shasum": "" 694 | }, 695 | "require": { 696 | "php": ">=7.1" 697 | }, 698 | "provide": { 699 | "ext-ctype": "*" 700 | }, 701 | "suggest": { 702 | "ext-ctype": "For best performance" 703 | }, 704 | "type": "library", 705 | "extra": { 706 | "thanks": { 707 | "name": "symfony/polyfill", 708 | "url": "https://github.com/symfony/polyfill" 709 | } 710 | }, 711 | "autoload": { 712 | "files": [ 713 | "bootstrap.php" 714 | ], 715 | "psr-4": { 716 | "Symfony\\Polyfill\\Ctype\\": "" 717 | } 718 | }, 719 | "notification-url": "https://packagist.org/downloads/", 720 | "license": [ 721 | "MIT" 722 | ], 723 | "authors": [ 724 | { 725 | "name": "Gert de Pagter", 726 | "email": "BackEndTea@gmail.com" 727 | }, 728 | { 729 | "name": "Symfony Community", 730 | "homepage": "https://symfony.com/contributors" 731 | } 732 | ], 733 | "description": "Symfony polyfill for ctype functions", 734 | "homepage": "https://symfony.com", 735 | "keywords": [ 736 | "compatibility", 737 | "ctype", 738 | "polyfill", 739 | "portable" 740 | ], 741 | "support": { 742 | "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0" 743 | }, 744 | "funding": [ 745 | { 746 | "url": "https://symfony.com/sponsor", 747 | "type": "custom" 748 | }, 749 | { 750 | "url": "https://github.com/fabpot", 751 | "type": "github" 752 | }, 753 | { 754 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 755 | "type": "tidelift" 756 | } 757 | ], 758 | "time": "2024-01-29T20:11:03+00:00" 759 | }, 760 | { 761 | "name": "symfony/polyfill-mbstring", 762 | "version": "v1.29.0", 763 | "source": { 764 | "type": "git", 765 | "url": "https://github.com/symfony/polyfill-mbstring.git", 766 | "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec" 767 | }, 768 | "dist": { 769 | "type": "zip", 770 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec", 771 | "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec", 772 | "shasum": "" 773 | }, 774 | "require": { 775 | "php": ">=7.1" 776 | }, 777 | "provide": { 778 | "ext-mbstring": "*" 779 | }, 780 | "suggest": { 781 | "ext-mbstring": "For best performance" 782 | }, 783 | "type": "library", 784 | "extra": { 785 | "thanks": { 786 | "name": "symfony/polyfill", 787 | "url": "https://github.com/symfony/polyfill" 788 | } 789 | }, 790 | "autoload": { 791 | "files": [ 792 | "bootstrap.php" 793 | ], 794 | "psr-4": { 795 | "Symfony\\Polyfill\\Mbstring\\": "" 796 | } 797 | }, 798 | "notification-url": "https://packagist.org/downloads/", 799 | "license": [ 800 | "MIT" 801 | ], 802 | "authors": [ 803 | { 804 | "name": "Nicolas Grekas", 805 | "email": "p@tchwork.com" 806 | }, 807 | { 808 | "name": "Symfony Community", 809 | "homepage": "https://symfony.com/contributors" 810 | } 811 | ], 812 | "description": "Symfony polyfill for the Mbstring extension", 813 | "homepage": "https://symfony.com", 814 | "keywords": [ 815 | "compatibility", 816 | "mbstring", 817 | "polyfill", 818 | "portable", 819 | "shim" 820 | ], 821 | "support": { 822 | "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0" 823 | }, 824 | "funding": [ 825 | { 826 | "url": "https://symfony.com/sponsor", 827 | "type": "custom" 828 | }, 829 | { 830 | "url": "https://github.com/fabpot", 831 | "type": "github" 832 | }, 833 | { 834 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 835 | "type": "tidelift" 836 | } 837 | ], 838 | "time": "2024-01-29T20:11:03+00:00" 839 | }, 840 | { 841 | "name": "symfony/service-contracts", 842 | "version": "v3.4.1", 843 | "source": { 844 | "type": "git", 845 | "url": "https://github.com/symfony/service-contracts.git", 846 | "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0" 847 | }, 848 | "dist": { 849 | "type": "zip", 850 | "url": "https://api.github.com/repos/symfony/service-contracts/zipball/fe07cbc8d837f60caf7018068e350cc5163681a0", 851 | "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0", 852 | "shasum": "" 853 | }, 854 | "require": { 855 | "php": ">=8.1", 856 | "psr/container": "^1.1|^2.0" 857 | }, 858 | "conflict": { 859 | "ext-psr": "<1.1|>=2" 860 | }, 861 | "type": "library", 862 | "extra": { 863 | "branch-alias": { 864 | "dev-main": "3.4-dev" 865 | }, 866 | "thanks": { 867 | "name": "symfony/contracts", 868 | "url": "https://github.com/symfony/contracts" 869 | } 870 | }, 871 | "autoload": { 872 | "psr-4": { 873 | "Symfony\\Contracts\\Service\\": "" 874 | }, 875 | "exclude-from-classmap": [ 876 | "/Test/" 877 | ] 878 | }, 879 | "notification-url": "https://packagist.org/downloads/", 880 | "license": [ 881 | "MIT" 882 | ], 883 | "authors": [ 884 | { 885 | "name": "Nicolas Grekas", 886 | "email": "p@tchwork.com" 887 | }, 888 | { 889 | "name": "Symfony Community", 890 | "homepage": "https://symfony.com/contributors" 891 | } 892 | ], 893 | "description": "Generic abstractions related to writing services", 894 | "homepage": "https://symfony.com", 895 | "keywords": [ 896 | "abstractions", 897 | "contracts", 898 | "decoupling", 899 | "interfaces", 900 | "interoperability", 901 | "standards" 902 | ], 903 | "support": { 904 | "source": "https://github.com/symfony/service-contracts/tree/v3.4.1" 905 | }, 906 | "funding": [ 907 | { 908 | "url": "https://symfony.com/sponsor", 909 | "type": "custom" 910 | }, 911 | { 912 | "url": "https://github.com/fabpot", 913 | "type": "github" 914 | }, 915 | { 916 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 917 | "type": "tidelift" 918 | } 919 | ], 920 | "time": "2023-12-26T14:02:43+00:00" 921 | }, 922 | { 923 | "name": "symfony/var-exporter", 924 | "version": "v7.0.3", 925 | "source": { 926 | "type": "git", 927 | "url": "https://github.com/symfony/var-exporter.git", 928 | "reference": "1fb79308cb5fc2b44bff6e8af10a5af6812e05b8" 929 | }, 930 | "dist": { 931 | "type": "zip", 932 | "url": "https://api.github.com/repos/symfony/var-exporter/zipball/1fb79308cb5fc2b44bff6e8af10a5af6812e05b8", 933 | "reference": "1fb79308cb5fc2b44bff6e8af10a5af6812e05b8", 934 | "shasum": "" 935 | }, 936 | "require": { 937 | "php": ">=8.2" 938 | }, 939 | "require-dev": { 940 | "symfony/var-dumper": "^6.4|^7.0" 941 | }, 942 | "type": "library", 943 | "autoload": { 944 | "psr-4": { 945 | "Symfony\\Component\\VarExporter\\": "" 946 | }, 947 | "exclude-from-classmap": [ 948 | "/Tests/" 949 | ] 950 | }, 951 | "notification-url": "https://packagist.org/downloads/", 952 | "license": [ 953 | "MIT" 954 | ], 955 | "authors": [ 956 | { 957 | "name": "Nicolas Grekas", 958 | "email": "p@tchwork.com" 959 | }, 960 | { 961 | "name": "Symfony Community", 962 | "homepage": "https://symfony.com/contributors" 963 | } 964 | ], 965 | "description": "Allows exporting any serializable PHP data structure to plain PHP code", 966 | "homepage": "https://symfony.com", 967 | "keywords": [ 968 | "clone", 969 | "construct", 970 | "export", 971 | "hydrate", 972 | "instantiate", 973 | "lazy-loading", 974 | "proxy", 975 | "serialize" 976 | ], 977 | "support": { 978 | "source": "https://github.com/symfony/var-exporter/tree/v7.0.3" 979 | }, 980 | "funding": [ 981 | { 982 | "url": "https://symfony.com/sponsor", 983 | "type": "custom" 984 | }, 985 | { 986 | "url": "https://github.com/fabpot", 987 | "type": "github" 988 | }, 989 | { 990 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 991 | "type": "tidelift" 992 | } 993 | ], 994 | "time": "2024-01-23T15:02:46+00:00" 995 | } 996 | ], 997 | "aliases": [], 998 | "minimum-stability": "stable", 999 | "stability-flags": [], 1000 | "prefer-stable": false, 1001 | "prefer-lowest": false, 1002 | "platform": [], 1003 | "platform-dev": [], 1004 | "plugin-api-version": "2.6.0" 1005 | } 1006 | -------------------------------------------------------------------------------- /examples/phpmd/src/Example.php: -------------------------------------------------------------------------------- 1 | 10) { 25 | echo "Number is greater than 10"; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/phpunit/.gitignore: -------------------------------------------------------------------------------- 1 | .phpunit.cache/ 2 | vendor/ 3 | -------------------------------------------------------------------------------- /examples/phpunit/README.md: -------------------------------------------------------------------------------- 1 | # PHPUnit 2 | 3 | This is an example to show how to run PHPUnit using `phpctl`. 4 | 5 | It is also a short tutorial on how to configure PhpStorm to run PHPUnit tests using the `phpctl` image. 6 | 7 | ## PhpStorm 8 | 9 | ### CLI Interpreter 10 | 11 | First we need to setup a Remote Interpreter to use `opencodeco/phpctl`. 12 | 13 | At the *Settings*, go to *Languages & Frameworks* and select *PHP*. 14 | 15 | Screenshot 2024-01-26 at 11 41 28 16 | 17 | Click on the 3 dots menus (`...`) on the right side of the window, at the *CLI Interpreter* option. 18 | 19 | Screenshot 2024-01-26 at 11 46 21 20 | 21 | Then click on the plus sign (`+`) button and choose *From Docker, Vagrant...*. 22 | 23 | Screenshot 2024-01-26 at 11 44 26 24 | 25 | Now choose the *Docker* option, select [your corresponding Docker server](https://www.jetbrains.com/help/phpstorm/docker.html#connect_to_docker), the `opencodeco/phpctl` image and at the *PHP interpreter path* just type `php`. 26 | 27 | Screenshot 2024-01-26 at 11 47 07 28 | 29 | Click **OK** to get the configured interpreter. 30 | 31 | Screenshot 2024-01-26 at 11 49 53 32 | 33 | Then just hit **OK** again. We are done. 34 | 35 | ### Test Frameworks 36 | 37 | At the *Settings*, go to *Languages & Frameworks*, open the *PHP* toggle and select *Test Frameworks*. 38 | 39 | Screenshot 2024-01-26 at 11 52 04 40 | 41 | Click on the plus sign button (`+`) and chosse *PHPUnit by Remote Interpreter*. 42 | 43 | Screenshot 2024-01-26 at 11 52 15 44 | 45 | Select the remote interpreter we just created. 46 | 47 | Screenshot 2024-01-26 at 11 52 31 48 | 49 | And click **OK**. 50 | 51 | Screenshot 2024-01-26 at 11 57 04 52 | 53 | Then click **OK** again. 54 | 55 | Inside a project, go to *Settings*, then *Languages & Frameworks*, open the *PHP* toggle and select *Test Frameworks* again. 56 | 57 | Screenshot 2024-01-26 at 11 57 49 58 | 59 | At the *PHPUnit library* we just need to configure the *Path to script* option. 60 | 61 | You should point it to your `vendor/autoload.php`, **but** keep in main that the path starts at `/opt/project` directory, that is the container's directory, not you host directory. 62 | 63 | In this case, the `phpctl` project root is at `/opt/project` then to point to the `vendor/autoload.php` from this example, we need to add the `examples/phpunit` directory. 64 | 65 | Screenshot 2024-01-26 at 11 59 13 66 | 67 | > [!NOTE] 68 | > Your configuration will probably be something simpler like `/opt/project/vendor/autoload.php`. 69 | 70 | Click **Apply** and **OK**. 71 | 72 | ### Run Configurations 73 | 74 | Now click on the top level menu *Run*. 75 | 76 | Screenshot 2024-01-26 at 12 06 07 77 | 78 | And select *Edit Configurations...* 79 | 80 | Screenshot 2024-01-26 at 12 06 18 81 | 82 | Click on the plus sign button (`+`) or *Add new...* 83 | 84 | Screenshot 2024-01-26 at 12 08 01 85 | 86 | And choose the *PHPUnit* configuration. 87 | 88 | Screenshot 2024-01-26 at 12 09 12 89 | 90 | Give it a good name, I'm calling this one as *PHPUnit Example* then: 91 | - At the *Test Runner* section, choose the *Defined in the configuration file* option. 92 | - Then enable the *Use alternative configuration file* option and point it to your `phpunit.xml` file. 93 | - At the *Command Line* section, in the *Interpreter* option, select the previus created interpreter `opencodeco/phpctl:php82`. 94 | 95 | Screenshot 2024-01-26 at 12 12 10 96 | 97 | Click **Apply** and **OK**. 98 | 99 | Now you can run the PHPUnit configuration we just created. 100 | 101 | Screenshot 2024-01-26 at 12 16 47 102 | 103 | And everything should ok fine. 104 | 105 | Screenshot 2024-01-26 at 12 17 37 106 | 107 | The command PhpStorm should be using will be something similar to: 108 | ```text 109 | [docker://opencodeco/phpctl:php82/]:php /opt/project/examples/phpunit/vendor/phpunit/phpunit/phpunit --configuration /opt/project/examples/phpunit/phpunit.xml --teamcity 110 | ``` 111 | 112 | --- 113 | 114 | Feel free to open any issues if any of these steps didn't worked well for you. 115 | -------------------------------------------------------------------------------- /examples/phpunit/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "autoload": { 3 | "psr-4": { 4 | "App\\": "src/" 5 | } 6 | }, 7 | "autoload-dev": { 8 | "psr-4": { 9 | "Test\\": "tests/" 10 | } 11 | }, 12 | "require-dev": { 13 | "phpunit/phpunit": "^10.5" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/phpunit/composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "edf908e1f6b0e4fca8854163be177e40", 8 | "packages": [], 9 | "packages-dev": [ 10 | { 11 | "name": "myclabs/deep-copy", 12 | "version": "1.11.1", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/myclabs/DeepCopy.git", 16 | "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", 21 | "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "php": "^7.1 || ^8.0" 26 | }, 27 | "conflict": { 28 | "doctrine/collections": "<1.6.8", 29 | "doctrine/common": "<2.13.3 || >=3,<3.2.2" 30 | }, 31 | "require-dev": { 32 | "doctrine/collections": "^1.6.8", 33 | "doctrine/common": "^2.13.3 || ^3.2.2", 34 | "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" 35 | }, 36 | "type": "library", 37 | "autoload": { 38 | "files": [ 39 | "src/DeepCopy/deep_copy.php" 40 | ], 41 | "psr-4": { 42 | "DeepCopy\\": "src/DeepCopy/" 43 | } 44 | }, 45 | "notification-url": "https://packagist.org/downloads/", 46 | "license": [ 47 | "MIT" 48 | ], 49 | "description": "Create deep copies (clones) of your objects", 50 | "keywords": [ 51 | "clone", 52 | "copy", 53 | "duplicate", 54 | "object", 55 | "object graph" 56 | ], 57 | "support": { 58 | "issues": "https://github.com/myclabs/DeepCopy/issues", 59 | "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" 60 | }, 61 | "funding": [ 62 | { 63 | "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", 64 | "type": "tidelift" 65 | } 66 | ], 67 | "time": "2023-03-08T13:26:56+00:00" 68 | }, 69 | { 70 | "name": "nikic/php-parser", 71 | "version": "v5.0.0", 72 | "source": { 73 | "type": "git", 74 | "url": "https://github.com/nikic/PHP-Parser.git", 75 | "reference": "4a21235f7e56e713259a6f76bf4b5ea08502b9dc" 76 | }, 77 | "dist": { 78 | "type": "zip", 79 | "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4a21235f7e56e713259a6f76bf4b5ea08502b9dc", 80 | "reference": "4a21235f7e56e713259a6f76bf4b5ea08502b9dc", 81 | "shasum": "" 82 | }, 83 | "require": { 84 | "ext-ctype": "*", 85 | "ext-json": "*", 86 | "ext-tokenizer": "*", 87 | "php": ">=7.4" 88 | }, 89 | "require-dev": { 90 | "ircmaxell/php-yacc": "^0.0.7", 91 | "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" 92 | }, 93 | "bin": [ 94 | "bin/php-parse" 95 | ], 96 | "type": "library", 97 | "extra": { 98 | "branch-alias": { 99 | "dev-master": "5.0-dev" 100 | } 101 | }, 102 | "autoload": { 103 | "psr-4": { 104 | "PhpParser\\": "lib/PhpParser" 105 | } 106 | }, 107 | "notification-url": "https://packagist.org/downloads/", 108 | "license": [ 109 | "BSD-3-Clause" 110 | ], 111 | "authors": [ 112 | { 113 | "name": "Nikita Popov" 114 | } 115 | ], 116 | "description": "A PHP parser written in PHP", 117 | "keywords": [ 118 | "parser", 119 | "php" 120 | ], 121 | "support": { 122 | "issues": "https://github.com/nikic/PHP-Parser/issues", 123 | "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.0" 124 | }, 125 | "time": "2024-01-07T17:17:35+00:00" 126 | }, 127 | { 128 | "name": "phar-io/manifest", 129 | "version": "2.0.3", 130 | "source": { 131 | "type": "git", 132 | "url": "https://github.com/phar-io/manifest.git", 133 | "reference": "97803eca37d319dfa7826cc2437fc020857acb53" 134 | }, 135 | "dist": { 136 | "type": "zip", 137 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", 138 | "reference": "97803eca37d319dfa7826cc2437fc020857acb53", 139 | "shasum": "" 140 | }, 141 | "require": { 142 | "ext-dom": "*", 143 | "ext-phar": "*", 144 | "ext-xmlwriter": "*", 145 | "phar-io/version": "^3.0.1", 146 | "php": "^7.2 || ^8.0" 147 | }, 148 | "type": "library", 149 | "extra": { 150 | "branch-alias": { 151 | "dev-master": "2.0.x-dev" 152 | } 153 | }, 154 | "autoload": { 155 | "classmap": [ 156 | "src/" 157 | ] 158 | }, 159 | "notification-url": "https://packagist.org/downloads/", 160 | "license": [ 161 | "BSD-3-Clause" 162 | ], 163 | "authors": [ 164 | { 165 | "name": "Arne Blankerts", 166 | "email": "arne@blankerts.de", 167 | "role": "Developer" 168 | }, 169 | { 170 | "name": "Sebastian Heuer", 171 | "email": "sebastian@phpeople.de", 172 | "role": "Developer" 173 | }, 174 | { 175 | "name": "Sebastian Bergmann", 176 | "email": "sebastian@phpunit.de", 177 | "role": "Developer" 178 | } 179 | ], 180 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", 181 | "support": { 182 | "issues": "https://github.com/phar-io/manifest/issues", 183 | "source": "https://github.com/phar-io/manifest/tree/2.0.3" 184 | }, 185 | "time": "2021-07-20T11:28:43+00:00" 186 | }, 187 | { 188 | "name": "phar-io/version", 189 | "version": "3.2.1", 190 | "source": { 191 | "type": "git", 192 | "url": "https://github.com/phar-io/version.git", 193 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" 194 | }, 195 | "dist": { 196 | "type": "zip", 197 | "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", 198 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", 199 | "shasum": "" 200 | }, 201 | "require": { 202 | "php": "^7.2 || ^8.0" 203 | }, 204 | "type": "library", 205 | "autoload": { 206 | "classmap": [ 207 | "src/" 208 | ] 209 | }, 210 | "notification-url": "https://packagist.org/downloads/", 211 | "license": [ 212 | "BSD-3-Clause" 213 | ], 214 | "authors": [ 215 | { 216 | "name": "Arne Blankerts", 217 | "email": "arne@blankerts.de", 218 | "role": "Developer" 219 | }, 220 | { 221 | "name": "Sebastian Heuer", 222 | "email": "sebastian@phpeople.de", 223 | "role": "Developer" 224 | }, 225 | { 226 | "name": "Sebastian Bergmann", 227 | "email": "sebastian@phpunit.de", 228 | "role": "Developer" 229 | } 230 | ], 231 | "description": "Library for handling version information and constraints", 232 | "support": { 233 | "issues": "https://github.com/phar-io/version/issues", 234 | "source": "https://github.com/phar-io/version/tree/3.2.1" 235 | }, 236 | "time": "2022-02-21T01:04:05+00:00" 237 | }, 238 | { 239 | "name": "phpunit/php-code-coverage", 240 | "version": "10.1.11", 241 | "source": { 242 | "type": "git", 243 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 244 | "reference": "78c3b7625965c2513ee96569a4dbb62601784145" 245 | }, 246 | "dist": { 247 | "type": "zip", 248 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/78c3b7625965c2513ee96569a4dbb62601784145", 249 | "reference": "78c3b7625965c2513ee96569a4dbb62601784145", 250 | "shasum": "" 251 | }, 252 | "require": { 253 | "ext-dom": "*", 254 | "ext-libxml": "*", 255 | "ext-xmlwriter": "*", 256 | "nikic/php-parser": "^4.18 || ^5.0", 257 | "php": ">=8.1", 258 | "phpunit/php-file-iterator": "^4.0", 259 | "phpunit/php-text-template": "^3.0", 260 | "sebastian/code-unit-reverse-lookup": "^3.0", 261 | "sebastian/complexity": "^3.0", 262 | "sebastian/environment": "^6.0", 263 | "sebastian/lines-of-code": "^2.0", 264 | "sebastian/version": "^4.0", 265 | "theseer/tokenizer": "^1.2.0" 266 | }, 267 | "require-dev": { 268 | "phpunit/phpunit": "^10.1" 269 | }, 270 | "suggest": { 271 | "ext-pcov": "PHP extension that provides line coverage", 272 | "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" 273 | }, 274 | "type": "library", 275 | "extra": { 276 | "branch-alias": { 277 | "dev-main": "10.1-dev" 278 | } 279 | }, 280 | "autoload": { 281 | "classmap": [ 282 | "src/" 283 | ] 284 | }, 285 | "notification-url": "https://packagist.org/downloads/", 286 | "license": [ 287 | "BSD-3-Clause" 288 | ], 289 | "authors": [ 290 | { 291 | "name": "Sebastian Bergmann", 292 | "email": "sebastian@phpunit.de", 293 | "role": "lead" 294 | } 295 | ], 296 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 297 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 298 | "keywords": [ 299 | "coverage", 300 | "testing", 301 | "xunit" 302 | ], 303 | "support": { 304 | "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", 305 | "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", 306 | "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.11" 307 | }, 308 | "funding": [ 309 | { 310 | "url": "https://github.com/sebastianbergmann", 311 | "type": "github" 312 | } 313 | ], 314 | "time": "2023-12-21T15:38:30+00:00" 315 | }, 316 | { 317 | "name": "phpunit/php-file-iterator", 318 | "version": "4.1.0", 319 | "source": { 320 | "type": "git", 321 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 322 | "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c" 323 | }, 324 | "dist": { 325 | "type": "zip", 326 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c", 327 | "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c", 328 | "shasum": "" 329 | }, 330 | "require": { 331 | "php": ">=8.1" 332 | }, 333 | "require-dev": { 334 | "phpunit/phpunit": "^10.0" 335 | }, 336 | "type": "library", 337 | "extra": { 338 | "branch-alias": { 339 | "dev-main": "4.0-dev" 340 | } 341 | }, 342 | "autoload": { 343 | "classmap": [ 344 | "src/" 345 | ] 346 | }, 347 | "notification-url": "https://packagist.org/downloads/", 348 | "license": [ 349 | "BSD-3-Clause" 350 | ], 351 | "authors": [ 352 | { 353 | "name": "Sebastian Bergmann", 354 | "email": "sebastian@phpunit.de", 355 | "role": "lead" 356 | } 357 | ], 358 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 359 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 360 | "keywords": [ 361 | "filesystem", 362 | "iterator" 363 | ], 364 | "support": { 365 | "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", 366 | "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", 367 | "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0" 368 | }, 369 | "funding": [ 370 | { 371 | "url": "https://github.com/sebastianbergmann", 372 | "type": "github" 373 | } 374 | ], 375 | "time": "2023-08-31T06:24:48+00:00" 376 | }, 377 | { 378 | "name": "phpunit/php-invoker", 379 | "version": "4.0.0", 380 | "source": { 381 | "type": "git", 382 | "url": "https://github.com/sebastianbergmann/php-invoker.git", 383 | "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7" 384 | }, 385 | "dist": { 386 | "type": "zip", 387 | "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", 388 | "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", 389 | "shasum": "" 390 | }, 391 | "require": { 392 | "php": ">=8.1" 393 | }, 394 | "require-dev": { 395 | "ext-pcntl": "*", 396 | "phpunit/phpunit": "^10.0" 397 | }, 398 | "suggest": { 399 | "ext-pcntl": "*" 400 | }, 401 | "type": "library", 402 | "extra": { 403 | "branch-alias": { 404 | "dev-main": "4.0-dev" 405 | } 406 | }, 407 | "autoload": { 408 | "classmap": [ 409 | "src/" 410 | ] 411 | }, 412 | "notification-url": "https://packagist.org/downloads/", 413 | "license": [ 414 | "BSD-3-Clause" 415 | ], 416 | "authors": [ 417 | { 418 | "name": "Sebastian Bergmann", 419 | "email": "sebastian@phpunit.de", 420 | "role": "lead" 421 | } 422 | ], 423 | "description": "Invoke callables with a timeout", 424 | "homepage": "https://github.com/sebastianbergmann/php-invoker/", 425 | "keywords": [ 426 | "process" 427 | ], 428 | "support": { 429 | "issues": "https://github.com/sebastianbergmann/php-invoker/issues", 430 | "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0" 431 | }, 432 | "funding": [ 433 | { 434 | "url": "https://github.com/sebastianbergmann", 435 | "type": "github" 436 | } 437 | ], 438 | "time": "2023-02-03T06:56:09+00:00" 439 | }, 440 | { 441 | "name": "phpunit/php-text-template", 442 | "version": "3.0.1", 443 | "source": { 444 | "type": "git", 445 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 446 | "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748" 447 | }, 448 | "dist": { 449 | "type": "zip", 450 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748", 451 | "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748", 452 | "shasum": "" 453 | }, 454 | "require": { 455 | "php": ">=8.1" 456 | }, 457 | "require-dev": { 458 | "phpunit/phpunit": "^10.0" 459 | }, 460 | "type": "library", 461 | "extra": { 462 | "branch-alias": { 463 | "dev-main": "3.0-dev" 464 | } 465 | }, 466 | "autoload": { 467 | "classmap": [ 468 | "src/" 469 | ] 470 | }, 471 | "notification-url": "https://packagist.org/downloads/", 472 | "license": [ 473 | "BSD-3-Clause" 474 | ], 475 | "authors": [ 476 | { 477 | "name": "Sebastian Bergmann", 478 | "email": "sebastian@phpunit.de", 479 | "role": "lead" 480 | } 481 | ], 482 | "description": "Simple template engine.", 483 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 484 | "keywords": [ 485 | "template" 486 | ], 487 | "support": { 488 | "issues": "https://github.com/sebastianbergmann/php-text-template/issues", 489 | "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", 490 | "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1" 491 | }, 492 | "funding": [ 493 | { 494 | "url": "https://github.com/sebastianbergmann", 495 | "type": "github" 496 | } 497 | ], 498 | "time": "2023-08-31T14:07:24+00:00" 499 | }, 500 | { 501 | "name": "phpunit/php-timer", 502 | "version": "6.0.0", 503 | "source": { 504 | "type": "git", 505 | "url": "https://github.com/sebastianbergmann/php-timer.git", 506 | "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d" 507 | }, 508 | "dist": { 509 | "type": "zip", 510 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d", 511 | "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d", 512 | "shasum": "" 513 | }, 514 | "require": { 515 | "php": ">=8.1" 516 | }, 517 | "require-dev": { 518 | "phpunit/phpunit": "^10.0" 519 | }, 520 | "type": "library", 521 | "extra": { 522 | "branch-alias": { 523 | "dev-main": "6.0-dev" 524 | } 525 | }, 526 | "autoload": { 527 | "classmap": [ 528 | "src/" 529 | ] 530 | }, 531 | "notification-url": "https://packagist.org/downloads/", 532 | "license": [ 533 | "BSD-3-Clause" 534 | ], 535 | "authors": [ 536 | { 537 | "name": "Sebastian Bergmann", 538 | "email": "sebastian@phpunit.de", 539 | "role": "lead" 540 | } 541 | ], 542 | "description": "Utility class for timing", 543 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 544 | "keywords": [ 545 | "timer" 546 | ], 547 | "support": { 548 | "issues": "https://github.com/sebastianbergmann/php-timer/issues", 549 | "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0" 550 | }, 551 | "funding": [ 552 | { 553 | "url": "https://github.com/sebastianbergmann", 554 | "type": "github" 555 | } 556 | ], 557 | "time": "2023-02-03T06:57:52+00:00" 558 | }, 559 | { 560 | "name": "phpunit/phpunit", 561 | "version": "10.5.9", 562 | "source": { 563 | "type": "git", 564 | "url": "https://github.com/sebastianbergmann/phpunit.git", 565 | "reference": "0bd663704f0165c9e76fe4f06ffa6a1ca727fdbe" 566 | }, 567 | "dist": { 568 | "type": "zip", 569 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0bd663704f0165c9e76fe4f06ffa6a1ca727fdbe", 570 | "reference": "0bd663704f0165c9e76fe4f06ffa6a1ca727fdbe", 571 | "shasum": "" 572 | }, 573 | "require": { 574 | "ext-dom": "*", 575 | "ext-json": "*", 576 | "ext-libxml": "*", 577 | "ext-mbstring": "*", 578 | "ext-xml": "*", 579 | "ext-xmlwriter": "*", 580 | "myclabs/deep-copy": "^1.10.1", 581 | "phar-io/manifest": "^2.0.3", 582 | "phar-io/version": "^3.0.2", 583 | "php": ">=8.1", 584 | "phpunit/php-code-coverage": "^10.1.5", 585 | "phpunit/php-file-iterator": "^4.0", 586 | "phpunit/php-invoker": "^4.0", 587 | "phpunit/php-text-template": "^3.0", 588 | "phpunit/php-timer": "^6.0", 589 | "sebastian/cli-parser": "^2.0", 590 | "sebastian/code-unit": "^2.0", 591 | "sebastian/comparator": "^5.0", 592 | "sebastian/diff": "^5.0", 593 | "sebastian/environment": "^6.0", 594 | "sebastian/exporter": "^5.1", 595 | "sebastian/global-state": "^6.0.1", 596 | "sebastian/object-enumerator": "^5.0", 597 | "sebastian/recursion-context": "^5.0", 598 | "sebastian/type": "^4.0", 599 | "sebastian/version": "^4.0" 600 | }, 601 | "suggest": { 602 | "ext-soap": "To be able to generate mocks based on WSDL files" 603 | }, 604 | "bin": [ 605 | "phpunit" 606 | ], 607 | "type": "library", 608 | "extra": { 609 | "branch-alias": { 610 | "dev-main": "10.5-dev" 611 | } 612 | }, 613 | "autoload": { 614 | "files": [ 615 | "src/Framework/Assert/Functions.php" 616 | ], 617 | "classmap": [ 618 | "src/" 619 | ] 620 | }, 621 | "notification-url": "https://packagist.org/downloads/", 622 | "license": [ 623 | "BSD-3-Clause" 624 | ], 625 | "authors": [ 626 | { 627 | "name": "Sebastian Bergmann", 628 | "email": "sebastian@phpunit.de", 629 | "role": "lead" 630 | } 631 | ], 632 | "description": "The PHP Unit Testing framework.", 633 | "homepage": "https://phpunit.de/", 634 | "keywords": [ 635 | "phpunit", 636 | "testing", 637 | "xunit" 638 | ], 639 | "support": { 640 | "issues": "https://github.com/sebastianbergmann/phpunit/issues", 641 | "security": "https://github.com/sebastianbergmann/phpunit/security/policy", 642 | "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.9" 643 | }, 644 | "funding": [ 645 | { 646 | "url": "https://phpunit.de/sponsors.html", 647 | "type": "custom" 648 | }, 649 | { 650 | "url": "https://github.com/sebastianbergmann", 651 | "type": "github" 652 | }, 653 | { 654 | "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", 655 | "type": "tidelift" 656 | } 657 | ], 658 | "time": "2024-01-22T14:35:40+00:00" 659 | }, 660 | { 661 | "name": "sebastian/cli-parser", 662 | "version": "2.0.0", 663 | "source": { 664 | "type": "git", 665 | "url": "https://github.com/sebastianbergmann/cli-parser.git", 666 | "reference": "efdc130dbbbb8ef0b545a994fd811725c5282cae" 667 | }, 668 | "dist": { 669 | "type": "zip", 670 | "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/efdc130dbbbb8ef0b545a994fd811725c5282cae", 671 | "reference": "efdc130dbbbb8ef0b545a994fd811725c5282cae", 672 | "shasum": "" 673 | }, 674 | "require": { 675 | "php": ">=8.1" 676 | }, 677 | "require-dev": { 678 | "phpunit/phpunit": "^10.0" 679 | }, 680 | "type": "library", 681 | "extra": { 682 | "branch-alias": { 683 | "dev-main": "2.0-dev" 684 | } 685 | }, 686 | "autoload": { 687 | "classmap": [ 688 | "src/" 689 | ] 690 | }, 691 | "notification-url": "https://packagist.org/downloads/", 692 | "license": [ 693 | "BSD-3-Clause" 694 | ], 695 | "authors": [ 696 | { 697 | "name": "Sebastian Bergmann", 698 | "email": "sebastian@phpunit.de", 699 | "role": "lead" 700 | } 701 | ], 702 | "description": "Library for parsing CLI options", 703 | "homepage": "https://github.com/sebastianbergmann/cli-parser", 704 | "support": { 705 | "issues": "https://github.com/sebastianbergmann/cli-parser/issues", 706 | "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.0" 707 | }, 708 | "funding": [ 709 | { 710 | "url": "https://github.com/sebastianbergmann", 711 | "type": "github" 712 | } 713 | ], 714 | "time": "2023-02-03T06:58:15+00:00" 715 | }, 716 | { 717 | "name": "sebastian/code-unit", 718 | "version": "2.0.0", 719 | "source": { 720 | "type": "git", 721 | "url": "https://github.com/sebastianbergmann/code-unit.git", 722 | "reference": "a81fee9eef0b7a76af11d121767abc44c104e503" 723 | }, 724 | "dist": { 725 | "type": "zip", 726 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503", 727 | "reference": "a81fee9eef0b7a76af11d121767abc44c104e503", 728 | "shasum": "" 729 | }, 730 | "require": { 731 | "php": ">=8.1" 732 | }, 733 | "require-dev": { 734 | "phpunit/phpunit": "^10.0" 735 | }, 736 | "type": "library", 737 | "extra": { 738 | "branch-alias": { 739 | "dev-main": "2.0-dev" 740 | } 741 | }, 742 | "autoload": { 743 | "classmap": [ 744 | "src/" 745 | ] 746 | }, 747 | "notification-url": "https://packagist.org/downloads/", 748 | "license": [ 749 | "BSD-3-Clause" 750 | ], 751 | "authors": [ 752 | { 753 | "name": "Sebastian Bergmann", 754 | "email": "sebastian@phpunit.de", 755 | "role": "lead" 756 | } 757 | ], 758 | "description": "Collection of value objects that represent the PHP code units", 759 | "homepage": "https://github.com/sebastianbergmann/code-unit", 760 | "support": { 761 | "issues": "https://github.com/sebastianbergmann/code-unit/issues", 762 | "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0" 763 | }, 764 | "funding": [ 765 | { 766 | "url": "https://github.com/sebastianbergmann", 767 | "type": "github" 768 | } 769 | ], 770 | "time": "2023-02-03T06:58:43+00:00" 771 | }, 772 | { 773 | "name": "sebastian/code-unit-reverse-lookup", 774 | "version": "3.0.0", 775 | "source": { 776 | "type": "git", 777 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", 778 | "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d" 779 | }, 780 | "dist": { 781 | "type": "zip", 782 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", 783 | "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", 784 | "shasum": "" 785 | }, 786 | "require": { 787 | "php": ">=8.1" 788 | }, 789 | "require-dev": { 790 | "phpunit/phpunit": "^10.0" 791 | }, 792 | "type": "library", 793 | "extra": { 794 | "branch-alias": { 795 | "dev-main": "3.0-dev" 796 | } 797 | }, 798 | "autoload": { 799 | "classmap": [ 800 | "src/" 801 | ] 802 | }, 803 | "notification-url": "https://packagist.org/downloads/", 804 | "license": [ 805 | "BSD-3-Clause" 806 | ], 807 | "authors": [ 808 | { 809 | "name": "Sebastian Bergmann", 810 | "email": "sebastian@phpunit.de" 811 | } 812 | ], 813 | "description": "Looks up which function or method a line of code belongs to", 814 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", 815 | "support": { 816 | "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", 817 | "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0" 818 | }, 819 | "funding": [ 820 | { 821 | "url": "https://github.com/sebastianbergmann", 822 | "type": "github" 823 | } 824 | ], 825 | "time": "2023-02-03T06:59:15+00:00" 826 | }, 827 | { 828 | "name": "sebastian/comparator", 829 | "version": "5.0.1", 830 | "source": { 831 | "type": "git", 832 | "url": "https://github.com/sebastianbergmann/comparator.git", 833 | "reference": "2db5010a484d53ebf536087a70b4a5423c102372" 834 | }, 835 | "dist": { 836 | "type": "zip", 837 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2db5010a484d53ebf536087a70b4a5423c102372", 838 | "reference": "2db5010a484d53ebf536087a70b4a5423c102372", 839 | "shasum": "" 840 | }, 841 | "require": { 842 | "ext-dom": "*", 843 | "ext-mbstring": "*", 844 | "php": ">=8.1", 845 | "sebastian/diff": "^5.0", 846 | "sebastian/exporter": "^5.0" 847 | }, 848 | "require-dev": { 849 | "phpunit/phpunit": "^10.3" 850 | }, 851 | "type": "library", 852 | "extra": { 853 | "branch-alias": { 854 | "dev-main": "5.0-dev" 855 | } 856 | }, 857 | "autoload": { 858 | "classmap": [ 859 | "src/" 860 | ] 861 | }, 862 | "notification-url": "https://packagist.org/downloads/", 863 | "license": [ 864 | "BSD-3-Clause" 865 | ], 866 | "authors": [ 867 | { 868 | "name": "Sebastian Bergmann", 869 | "email": "sebastian@phpunit.de" 870 | }, 871 | { 872 | "name": "Jeff Welch", 873 | "email": "whatthejeff@gmail.com" 874 | }, 875 | { 876 | "name": "Volker Dusch", 877 | "email": "github@wallbash.com" 878 | }, 879 | { 880 | "name": "Bernhard Schussek", 881 | "email": "bschussek@2bepublished.at" 882 | } 883 | ], 884 | "description": "Provides the functionality to compare PHP values for equality", 885 | "homepage": "https://github.com/sebastianbergmann/comparator", 886 | "keywords": [ 887 | "comparator", 888 | "compare", 889 | "equality" 890 | ], 891 | "support": { 892 | "issues": "https://github.com/sebastianbergmann/comparator/issues", 893 | "security": "https://github.com/sebastianbergmann/comparator/security/policy", 894 | "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.1" 895 | }, 896 | "funding": [ 897 | { 898 | "url": "https://github.com/sebastianbergmann", 899 | "type": "github" 900 | } 901 | ], 902 | "time": "2023-08-14T13:18:12+00:00" 903 | }, 904 | { 905 | "name": "sebastian/complexity", 906 | "version": "3.2.0", 907 | "source": { 908 | "type": "git", 909 | "url": "https://github.com/sebastianbergmann/complexity.git", 910 | "reference": "68ff824baeae169ec9f2137158ee529584553799" 911 | }, 912 | "dist": { 913 | "type": "zip", 914 | "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799", 915 | "reference": "68ff824baeae169ec9f2137158ee529584553799", 916 | "shasum": "" 917 | }, 918 | "require": { 919 | "nikic/php-parser": "^4.18 || ^5.0", 920 | "php": ">=8.1" 921 | }, 922 | "require-dev": { 923 | "phpunit/phpunit": "^10.0" 924 | }, 925 | "type": "library", 926 | "extra": { 927 | "branch-alias": { 928 | "dev-main": "3.2-dev" 929 | } 930 | }, 931 | "autoload": { 932 | "classmap": [ 933 | "src/" 934 | ] 935 | }, 936 | "notification-url": "https://packagist.org/downloads/", 937 | "license": [ 938 | "BSD-3-Clause" 939 | ], 940 | "authors": [ 941 | { 942 | "name": "Sebastian Bergmann", 943 | "email": "sebastian@phpunit.de", 944 | "role": "lead" 945 | } 946 | ], 947 | "description": "Library for calculating the complexity of PHP code units", 948 | "homepage": "https://github.com/sebastianbergmann/complexity", 949 | "support": { 950 | "issues": "https://github.com/sebastianbergmann/complexity/issues", 951 | "security": "https://github.com/sebastianbergmann/complexity/security/policy", 952 | "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0" 953 | }, 954 | "funding": [ 955 | { 956 | "url": "https://github.com/sebastianbergmann", 957 | "type": "github" 958 | } 959 | ], 960 | "time": "2023-12-21T08:37:17+00:00" 961 | }, 962 | { 963 | "name": "sebastian/diff", 964 | "version": "5.1.0", 965 | "source": { 966 | "type": "git", 967 | "url": "https://github.com/sebastianbergmann/diff.git", 968 | "reference": "fbf413a49e54f6b9b17e12d900ac7f6101591b7f" 969 | }, 970 | "dist": { 971 | "type": "zip", 972 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/fbf413a49e54f6b9b17e12d900ac7f6101591b7f", 973 | "reference": "fbf413a49e54f6b9b17e12d900ac7f6101591b7f", 974 | "shasum": "" 975 | }, 976 | "require": { 977 | "php": ">=8.1" 978 | }, 979 | "require-dev": { 980 | "phpunit/phpunit": "^10.0", 981 | "symfony/process": "^4.2 || ^5" 982 | }, 983 | "type": "library", 984 | "extra": { 985 | "branch-alias": { 986 | "dev-main": "5.1-dev" 987 | } 988 | }, 989 | "autoload": { 990 | "classmap": [ 991 | "src/" 992 | ] 993 | }, 994 | "notification-url": "https://packagist.org/downloads/", 995 | "license": [ 996 | "BSD-3-Clause" 997 | ], 998 | "authors": [ 999 | { 1000 | "name": "Sebastian Bergmann", 1001 | "email": "sebastian@phpunit.de" 1002 | }, 1003 | { 1004 | "name": "Kore Nordmann", 1005 | "email": "mail@kore-nordmann.de" 1006 | } 1007 | ], 1008 | "description": "Diff implementation", 1009 | "homepage": "https://github.com/sebastianbergmann/diff", 1010 | "keywords": [ 1011 | "diff", 1012 | "udiff", 1013 | "unidiff", 1014 | "unified diff" 1015 | ], 1016 | "support": { 1017 | "issues": "https://github.com/sebastianbergmann/diff/issues", 1018 | "security": "https://github.com/sebastianbergmann/diff/security/policy", 1019 | "source": "https://github.com/sebastianbergmann/diff/tree/5.1.0" 1020 | }, 1021 | "funding": [ 1022 | { 1023 | "url": "https://github.com/sebastianbergmann", 1024 | "type": "github" 1025 | } 1026 | ], 1027 | "time": "2023-12-22T10:55:06+00:00" 1028 | }, 1029 | { 1030 | "name": "sebastian/environment", 1031 | "version": "6.0.1", 1032 | "source": { 1033 | "type": "git", 1034 | "url": "https://github.com/sebastianbergmann/environment.git", 1035 | "reference": "43c751b41d74f96cbbd4e07b7aec9675651e2951" 1036 | }, 1037 | "dist": { 1038 | "type": "zip", 1039 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/43c751b41d74f96cbbd4e07b7aec9675651e2951", 1040 | "reference": "43c751b41d74f96cbbd4e07b7aec9675651e2951", 1041 | "shasum": "" 1042 | }, 1043 | "require": { 1044 | "php": ">=8.1" 1045 | }, 1046 | "require-dev": { 1047 | "phpunit/phpunit": "^10.0" 1048 | }, 1049 | "suggest": { 1050 | "ext-posix": "*" 1051 | }, 1052 | "type": "library", 1053 | "extra": { 1054 | "branch-alias": { 1055 | "dev-main": "6.0-dev" 1056 | } 1057 | }, 1058 | "autoload": { 1059 | "classmap": [ 1060 | "src/" 1061 | ] 1062 | }, 1063 | "notification-url": "https://packagist.org/downloads/", 1064 | "license": [ 1065 | "BSD-3-Clause" 1066 | ], 1067 | "authors": [ 1068 | { 1069 | "name": "Sebastian Bergmann", 1070 | "email": "sebastian@phpunit.de" 1071 | } 1072 | ], 1073 | "description": "Provides functionality to handle HHVM/PHP environments", 1074 | "homepage": "https://github.com/sebastianbergmann/environment", 1075 | "keywords": [ 1076 | "Xdebug", 1077 | "environment", 1078 | "hhvm" 1079 | ], 1080 | "support": { 1081 | "issues": "https://github.com/sebastianbergmann/environment/issues", 1082 | "security": "https://github.com/sebastianbergmann/environment/security/policy", 1083 | "source": "https://github.com/sebastianbergmann/environment/tree/6.0.1" 1084 | }, 1085 | "funding": [ 1086 | { 1087 | "url": "https://github.com/sebastianbergmann", 1088 | "type": "github" 1089 | } 1090 | ], 1091 | "time": "2023-04-11T05:39:26+00:00" 1092 | }, 1093 | { 1094 | "name": "sebastian/exporter", 1095 | "version": "5.1.1", 1096 | "source": { 1097 | "type": "git", 1098 | "url": "https://github.com/sebastianbergmann/exporter.git", 1099 | "reference": "64f51654862e0f5e318db7e9dcc2292c63cdbddc" 1100 | }, 1101 | "dist": { 1102 | "type": "zip", 1103 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/64f51654862e0f5e318db7e9dcc2292c63cdbddc", 1104 | "reference": "64f51654862e0f5e318db7e9dcc2292c63cdbddc", 1105 | "shasum": "" 1106 | }, 1107 | "require": { 1108 | "ext-mbstring": "*", 1109 | "php": ">=8.1", 1110 | "sebastian/recursion-context": "^5.0" 1111 | }, 1112 | "require-dev": { 1113 | "phpunit/phpunit": "^10.0" 1114 | }, 1115 | "type": "library", 1116 | "extra": { 1117 | "branch-alias": { 1118 | "dev-main": "5.1-dev" 1119 | } 1120 | }, 1121 | "autoload": { 1122 | "classmap": [ 1123 | "src/" 1124 | ] 1125 | }, 1126 | "notification-url": "https://packagist.org/downloads/", 1127 | "license": [ 1128 | "BSD-3-Clause" 1129 | ], 1130 | "authors": [ 1131 | { 1132 | "name": "Sebastian Bergmann", 1133 | "email": "sebastian@phpunit.de" 1134 | }, 1135 | { 1136 | "name": "Jeff Welch", 1137 | "email": "whatthejeff@gmail.com" 1138 | }, 1139 | { 1140 | "name": "Volker Dusch", 1141 | "email": "github@wallbash.com" 1142 | }, 1143 | { 1144 | "name": "Adam Harvey", 1145 | "email": "aharvey@php.net" 1146 | }, 1147 | { 1148 | "name": "Bernhard Schussek", 1149 | "email": "bschussek@gmail.com" 1150 | } 1151 | ], 1152 | "description": "Provides the functionality to export PHP variables for visualization", 1153 | "homepage": "https://www.github.com/sebastianbergmann/exporter", 1154 | "keywords": [ 1155 | "export", 1156 | "exporter" 1157 | ], 1158 | "support": { 1159 | "issues": "https://github.com/sebastianbergmann/exporter/issues", 1160 | "security": "https://github.com/sebastianbergmann/exporter/security/policy", 1161 | "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.1" 1162 | }, 1163 | "funding": [ 1164 | { 1165 | "url": "https://github.com/sebastianbergmann", 1166 | "type": "github" 1167 | } 1168 | ], 1169 | "time": "2023-09-24T13:22:09+00:00" 1170 | }, 1171 | { 1172 | "name": "sebastian/global-state", 1173 | "version": "6.0.1", 1174 | "source": { 1175 | "type": "git", 1176 | "url": "https://github.com/sebastianbergmann/global-state.git", 1177 | "reference": "7ea9ead78f6d380d2a667864c132c2f7b83055e4" 1178 | }, 1179 | "dist": { 1180 | "type": "zip", 1181 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/7ea9ead78f6d380d2a667864c132c2f7b83055e4", 1182 | "reference": "7ea9ead78f6d380d2a667864c132c2f7b83055e4", 1183 | "shasum": "" 1184 | }, 1185 | "require": { 1186 | "php": ">=8.1", 1187 | "sebastian/object-reflector": "^3.0", 1188 | "sebastian/recursion-context": "^5.0" 1189 | }, 1190 | "require-dev": { 1191 | "ext-dom": "*", 1192 | "phpunit/phpunit": "^10.0" 1193 | }, 1194 | "type": "library", 1195 | "extra": { 1196 | "branch-alias": { 1197 | "dev-main": "6.0-dev" 1198 | } 1199 | }, 1200 | "autoload": { 1201 | "classmap": [ 1202 | "src/" 1203 | ] 1204 | }, 1205 | "notification-url": "https://packagist.org/downloads/", 1206 | "license": [ 1207 | "BSD-3-Clause" 1208 | ], 1209 | "authors": [ 1210 | { 1211 | "name": "Sebastian Bergmann", 1212 | "email": "sebastian@phpunit.de" 1213 | } 1214 | ], 1215 | "description": "Snapshotting of global state", 1216 | "homepage": "http://www.github.com/sebastianbergmann/global-state", 1217 | "keywords": [ 1218 | "global state" 1219 | ], 1220 | "support": { 1221 | "issues": "https://github.com/sebastianbergmann/global-state/issues", 1222 | "security": "https://github.com/sebastianbergmann/global-state/security/policy", 1223 | "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.1" 1224 | }, 1225 | "funding": [ 1226 | { 1227 | "url": "https://github.com/sebastianbergmann", 1228 | "type": "github" 1229 | } 1230 | ], 1231 | "time": "2023-07-19T07:19:23+00:00" 1232 | }, 1233 | { 1234 | "name": "sebastian/lines-of-code", 1235 | "version": "2.0.2", 1236 | "source": { 1237 | "type": "git", 1238 | "url": "https://github.com/sebastianbergmann/lines-of-code.git", 1239 | "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0" 1240 | }, 1241 | "dist": { 1242 | "type": "zip", 1243 | "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0", 1244 | "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0", 1245 | "shasum": "" 1246 | }, 1247 | "require": { 1248 | "nikic/php-parser": "^4.18 || ^5.0", 1249 | "php": ">=8.1" 1250 | }, 1251 | "require-dev": { 1252 | "phpunit/phpunit": "^10.0" 1253 | }, 1254 | "type": "library", 1255 | "extra": { 1256 | "branch-alias": { 1257 | "dev-main": "2.0-dev" 1258 | } 1259 | }, 1260 | "autoload": { 1261 | "classmap": [ 1262 | "src/" 1263 | ] 1264 | }, 1265 | "notification-url": "https://packagist.org/downloads/", 1266 | "license": [ 1267 | "BSD-3-Clause" 1268 | ], 1269 | "authors": [ 1270 | { 1271 | "name": "Sebastian Bergmann", 1272 | "email": "sebastian@phpunit.de", 1273 | "role": "lead" 1274 | } 1275 | ], 1276 | "description": "Library for counting the lines of code in PHP source code", 1277 | "homepage": "https://github.com/sebastianbergmann/lines-of-code", 1278 | "support": { 1279 | "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", 1280 | "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", 1281 | "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2" 1282 | }, 1283 | "funding": [ 1284 | { 1285 | "url": "https://github.com/sebastianbergmann", 1286 | "type": "github" 1287 | } 1288 | ], 1289 | "time": "2023-12-21T08:38:20+00:00" 1290 | }, 1291 | { 1292 | "name": "sebastian/object-enumerator", 1293 | "version": "5.0.0", 1294 | "source": { 1295 | "type": "git", 1296 | "url": "https://github.com/sebastianbergmann/object-enumerator.git", 1297 | "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906" 1298 | }, 1299 | "dist": { 1300 | "type": "zip", 1301 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906", 1302 | "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906", 1303 | "shasum": "" 1304 | }, 1305 | "require": { 1306 | "php": ">=8.1", 1307 | "sebastian/object-reflector": "^3.0", 1308 | "sebastian/recursion-context": "^5.0" 1309 | }, 1310 | "require-dev": { 1311 | "phpunit/phpunit": "^10.0" 1312 | }, 1313 | "type": "library", 1314 | "extra": { 1315 | "branch-alias": { 1316 | "dev-main": "5.0-dev" 1317 | } 1318 | }, 1319 | "autoload": { 1320 | "classmap": [ 1321 | "src/" 1322 | ] 1323 | }, 1324 | "notification-url": "https://packagist.org/downloads/", 1325 | "license": [ 1326 | "BSD-3-Clause" 1327 | ], 1328 | "authors": [ 1329 | { 1330 | "name": "Sebastian Bergmann", 1331 | "email": "sebastian@phpunit.de" 1332 | } 1333 | ], 1334 | "description": "Traverses array structures and object graphs to enumerate all referenced objects", 1335 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/", 1336 | "support": { 1337 | "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", 1338 | "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0" 1339 | }, 1340 | "funding": [ 1341 | { 1342 | "url": "https://github.com/sebastianbergmann", 1343 | "type": "github" 1344 | } 1345 | ], 1346 | "time": "2023-02-03T07:08:32+00:00" 1347 | }, 1348 | { 1349 | "name": "sebastian/object-reflector", 1350 | "version": "3.0.0", 1351 | "source": { 1352 | "type": "git", 1353 | "url": "https://github.com/sebastianbergmann/object-reflector.git", 1354 | "reference": "24ed13d98130f0e7122df55d06c5c4942a577957" 1355 | }, 1356 | "dist": { 1357 | "type": "zip", 1358 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957", 1359 | "reference": "24ed13d98130f0e7122df55d06c5c4942a577957", 1360 | "shasum": "" 1361 | }, 1362 | "require": { 1363 | "php": ">=8.1" 1364 | }, 1365 | "require-dev": { 1366 | "phpunit/phpunit": "^10.0" 1367 | }, 1368 | "type": "library", 1369 | "extra": { 1370 | "branch-alias": { 1371 | "dev-main": "3.0-dev" 1372 | } 1373 | }, 1374 | "autoload": { 1375 | "classmap": [ 1376 | "src/" 1377 | ] 1378 | }, 1379 | "notification-url": "https://packagist.org/downloads/", 1380 | "license": [ 1381 | "BSD-3-Clause" 1382 | ], 1383 | "authors": [ 1384 | { 1385 | "name": "Sebastian Bergmann", 1386 | "email": "sebastian@phpunit.de" 1387 | } 1388 | ], 1389 | "description": "Allows reflection of object attributes, including inherited and non-public ones", 1390 | "homepage": "https://github.com/sebastianbergmann/object-reflector/", 1391 | "support": { 1392 | "issues": "https://github.com/sebastianbergmann/object-reflector/issues", 1393 | "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0" 1394 | }, 1395 | "funding": [ 1396 | { 1397 | "url": "https://github.com/sebastianbergmann", 1398 | "type": "github" 1399 | } 1400 | ], 1401 | "time": "2023-02-03T07:06:18+00:00" 1402 | }, 1403 | { 1404 | "name": "sebastian/recursion-context", 1405 | "version": "5.0.0", 1406 | "source": { 1407 | "type": "git", 1408 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 1409 | "reference": "05909fb5bc7df4c52992396d0116aed689f93712" 1410 | }, 1411 | "dist": { 1412 | "type": "zip", 1413 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/05909fb5bc7df4c52992396d0116aed689f93712", 1414 | "reference": "05909fb5bc7df4c52992396d0116aed689f93712", 1415 | "shasum": "" 1416 | }, 1417 | "require": { 1418 | "php": ">=8.1" 1419 | }, 1420 | "require-dev": { 1421 | "phpunit/phpunit": "^10.0" 1422 | }, 1423 | "type": "library", 1424 | "extra": { 1425 | "branch-alias": { 1426 | "dev-main": "5.0-dev" 1427 | } 1428 | }, 1429 | "autoload": { 1430 | "classmap": [ 1431 | "src/" 1432 | ] 1433 | }, 1434 | "notification-url": "https://packagist.org/downloads/", 1435 | "license": [ 1436 | "BSD-3-Clause" 1437 | ], 1438 | "authors": [ 1439 | { 1440 | "name": "Sebastian Bergmann", 1441 | "email": "sebastian@phpunit.de" 1442 | }, 1443 | { 1444 | "name": "Jeff Welch", 1445 | "email": "whatthejeff@gmail.com" 1446 | }, 1447 | { 1448 | "name": "Adam Harvey", 1449 | "email": "aharvey@php.net" 1450 | } 1451 | ], 1452 | "description": "Provides functionality to recursively process PHP variables", 1453 | "homepage": "https://github.com/sebastianbergmann/recursion-context", 1454 | "support": { 1455 | "issues": "https://github.com/sebastianbergmann/recursion-context/issues", 1456 | "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.0" 1457 | }, 1458 | "funding": [ 1459 | { 1460 | "url": "https://github.com/sebastianbergmann", 1461 | "type": "github" 1462 | } 1463 | ], 1464 | "time": "2023-02-03T07:05:40+00:00" 1465 | }, 1466 | { 1467 | "name": "sebastian/type", 1468 | "version": "4.0.0", 1469 | "source": { 1470 | "type": "git", 1471 | "url": "https://github.com/sebastianbergmann/type.git", 1472 | "reference": "462699a16464c3944eefc02ebdd77882bd3925bf" 1473 | }, 1474 | "dist": { 1475 | "type": "zip", 1476 | "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf", 1477 | "reference": "462699a16464c3944eefc02ebdd77882bd3925bf", 1478 | "shasum": "" 1479 | }, 1480 | "require": { 1481 | "php": ">=8.1" 1482 | }, 1483 | "require-dev": { 1484 | "phpunit/phpunit": "^10.0" 1485 | }, 1486 | "type": "library", 1487 | "extra": { 1488 | "branch-alias": { 1489 | "dev-main": "4.0-dev" 1490 | } 1491 | }, 1492 | "autoload": { 1493 | "classmap": [ 1494 | "src/" 1495 | ] 1496 | }, 1497 | "notification-url": "https://packagist.org/downloads/", 1498 | "license": [ 1499 | "BSD-3-Clause" 1500 | ], 1501 | "authors": [ 1502 | { 1503 | "name": "Sebastian Bergmann", 1504 | "email": "sebastian@phpunit.de", 1505 | "role": "lead" 1506 | } 1507 | ], 1508 | "description": "Collection of value objects that represent the types of the PHP type system", 1509 | "homepage": "https://github.com/sebastianbergmann/type", 1510 | "support": { 1511 | "issues": "https://github.com/sebastianbergmann/type/issues", 1512 | "source": "https://github.com/sebastianbergmann/type/tree/4.0.0" 1513 | }, 1514 | "funding": [ 1515 | { 1516 | "url": "https://github.com/sebastianbergmann", 1517 | "type": "github" 1518 | } 1519 | ], 1520 | "time": "2023-02-03T07:10:45+00:00" 1521 | }, 1522 | { 1523 | "name": "sebastian/version", 1524 | "version": "4.0.1", 1525 | "source": { 1526 | "type": "git", 1527 | "url": "https://github.com/sebastianbergmann/version.git", 1528 | "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17" 1529 | }, 1530 | "dist": { 1531 | "type": "zip", 1532 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17", 1533 | "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17", 1534 | "shasum": "" 1535 | }, 1536 | "require": { 1537 | "php": ">=8.1" 1538 | }, 1539 | "type": "library", 1540 | "extra": { 1541 | "branch-alias": { 1542 | "dev-main": "4.0-dev" 1543 | } 1544 | }, 1545 | "autoload": { 1546 | "classmap": [ 1547 | "src/" 1548 | ] 1549 | }, 1550 | "notification-url": "https://packagist.org/downloads/", 1551 | "license": [ 1552 | "BSD-3-Clause" 1553 | ], 1554 | "authors": [ 1555 | { 1556 | "name": "Sebastian Bergmann", 1557 | "email": "sebastian@phpunit.de", 1558 | "role": "lead" 1559 | } 1560 | ], 1561 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 1562 | "homepage": "https://github.com/sebastianbergmann/version", 1563 | "support": { 1564 | "issues": "https://github.com/sebastianbergmann/version/issues", 1565 | "source": "https://github.com/sebastianbergmann/version/tree/4.0.1" 1566 | }, 1567 | "funding": [ 1568 | { 1569 | "url": "https://github.com/sebastianbergmann", 1570 | "type": "github" 1571 | } 1572 | ], 1573 | "time": "2023-02-07T11:34:05+00:00" 1574 | }, 1575 | { 1576 | "name": "theseer/tokenizer", 1577 | "version": "1.2.2", 1578 | "source": { 1579 | "type": "git", 1580 | "url": "https://github.com/theseer/tokenizer.git", 1581 | "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96" 1582 | }, 1583 | "dist": { 1584 | "type": "zip", 1585 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96", 1586 | "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96", 1587 | "shasum": "" 1588 | }, 1589 | "require": { 1590 | "ext-dom": "*", 1591 | "ext-tokenizer": "*", 1592 | "ext-xmlwriter": "*", 1593 | "php": "^7.2 || ^8.0" 1594 | }, 1595 | "type": "library", 1596 | "autoload": { 1597 | "classmap": [ 1598 | "src/" 1599 | ] 1600 | }, 1601 | "notification-url": "https://packagist.org/downloads/", 1602 | "license": [ 1603 | "BSD-3-Clause" 1604 | ], 1605 | "authors": [ 1606 | { 1607 | "name": "Arne Blankerts", 1608 | "email": "arne@blankerts.de", 1609 | "role": "Developer" 1610 | } 1611 | ], 1612 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", 1613 | "support": { 1614 | "issues": "https://github.com/theseer/tokenizer/issues", 1615 | "source": "https://github.com/theseer/tokenizer/tree/1.2.2" 1616 | }, 1617 | "funding": [ 1618 | { 1619 | "url": "https://github.com/theseer", 1620 | "type": "github" 1621 | } 1622 | ], 1623 | "time": "2023-11-20T00:12:19+00:00" 1624 | } 1625 | ], 1626 | "aliases": [], 1627 | "minimum-stability": "stable", 1628 | "stability-flags": [], 1629 | "prefer-stable": false, 1630 | "prefer-lowest": false, 1631 | "platform": [], 1632 | "platform-dev": [], 1633 | "plugin-api-version": "2.6.0" 1634 | } 1635 | -------------------------------------------------------------------------------- /examples/phpunit/phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | tests 15 | 16 | 17 | 18 | 19 | 20 | src 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /examples/phpunit/src/Example.php: -------------------------------------------------------------------------------- 1 | whatIsTheBestDevEnvForPhp()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/rector/.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | -------------------------------------------------------------------------------- /examples/rector/README.md: -------------------------------------------------------------------------------- 1 | # Rector 2 | 3 | This is an example of how to use Rector to refactor your code. 4 | 5 | Run `phpctl rector -n` (yes, with the `-n` flag) to see what Rector would do. 6 | 7 | You should be seeing something like: 8 | ```shell 9 | ➜ rector git:(feat/rector) ✗ phpctl rector -n 10 | Running opencodeco/phpctl:php82 11 | 1/1 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100% 12 | 1 file with changes 13 | =================== 14 | 15 | 1) src/example.php:0 16 | 17 | ---------- begin diff ---------- 18 | @@ @@ 19 | paths([ 11 | __DIR__ . '/src', 12 | ]); 13 | 14 | // register a single rule 15 | $rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class); 16 | 17 | // define sets of rules 18 | $rectorConfig->sets([ 19 | LevelSetList::UP_TO_PHP_82 20 | ]); 21 | }; 22 | -------------------------------------------------------------------------------- /examples/rector/src/example.php: -------------------------------------------------------------------------------- 1 | on(\Swoole\Constant::EVENT_REQUEST, function (\Swoole\Http\Request $req, \Swoole\Http\Response $res) { 10 | $res->end('Hello, World!'); 11 | }); 12 | 13 | $srv->on(\Swoole\Constant::EVENT_START, function (\Swoole\Http\Server $srv) { 14 | echo "Server started at http://localhost:{$srv->port}\n"; 15 | }); 16 | 17 | $srv->start(); 18 | -------------------------------------------------------------------------------- /examples/xdebug/README.md: -------------------------------------------------------------------------------- 1 | # Xdebug 2 | 3 | This is an example on how you can enable and configure Xdebug to work with `phpctl` at your PHP application. 4 | 5 | ## How-to 6 | 7 | Xdebug is already shipped within `phpctl`, you just need to enable it. 8 | 9 | You can do so by using a `phpctl.ini` file where `phpctl` will be running. 10 | 11 | If you run `phpctl php -v` at this directory, you will see that Xdebug is installed. 12 | 13 | ```shell 14 | phpctl php -v 15 | ``` 16 | 17 | ```shell 18 | PHP 8.2.15 (cli) (built: Jan 18 2024 16:40:05) (NTS) 19 | Copyright (c) The PHP Group 20 | Zend Engine v4.2.15, Copyright (c) Zend Technologies 21 | with Xdebug v3.3.1, Copyright (c) 2002-2023, by Derick Rethans 22 | ``` 23 | 24 | This is because of the `phpctl.ini` file at this directory with the following contents: 25 | 26 | ```ini 27 | zend_extension=xdebug 28 | 29 | [xdebug] 30 | xdebug.mode = develop,debug 31 | xdebug.log = /tmp/xdebug.log 32 | xdebug.start_with_request = Yes 33 | ``` 34 | 35 | > [!TIP] 36 | > You can use `phpctl.ini` file to change any another PHP INI directive, not just Xdebug. 37 | -------------------------------------------------------------------------------- /examples/xdebug/phpctl.ini: -------------------------------------------------------------------------------- 1 | zend_extension=xdebug 2 | 3 | [xdebug] 4 | xdebug.mode = develop,debug 5 | xdebug.log = /tmp/xdebug.log 6 | xdebug.start_with_request = Yes 7 | -------------------------------------------------------------------------------- /frankenphp.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM dunglas/frankenphp 2 | RUN install-php-extensions pcntl swoole 3 | -------------------------------------------------------------------------------- /php.ini: -------------------------------------------------------------------------------- 1 | sys_temp_dir = /tmp 2 | -------------------------------------------------------------------------------- /rootfs/etc/php/php.ini: -------------------------------------------------------------------------------- 1 | memory_limit = -1 2 | sys_temp_dir = /tmp 3 | 4 | [swoole] 5 | swoole.use_shortname = Off 6 | 7 | [phar] 8 | phar.readonly = Off 9 | -------------------------------------------------------------------------------- /rootfs/usr/local/bin/install-swoole: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | set -e 3 | 4 | SWOOLE_VERSION="5.1.4" 5 | echo "Installing Swoole $SWOOLE_VERSION" 6 | 7 | # Download 8 | cd /usr/local/src 9 | wget -q "https://github.com/swoole/swoole-src/archive/refs/tags/v${SWOOLE_VERSION}.zip" 10 | unzip -q "v${SWOOLE_VERSION}.zip" 11 | 12 | # Install 13 | cd "swoole-src-${SWOOLE_VERSION}" 14 | phpize 15 | ./configure --enable-sockets --enable-openssl --enable-brotli --enable-mysqlnd --enable-cares --enable-swoole-curl --enable-swoole-pgsql --enable-swoole-sqlite 16 | make -j$(nproc) 17 | make install 18 | echo "extension=swoole.so" >> /usr/local/etc/php/conf.d/docker-php-ext-swoole.ini 19 | 20 | # Clean up 21 | cd .. 22 | rm "v${SWOOLE_VERSION}.zip" 23 | rm -r "swoole-src-${SWOOLE_VERSION}" 24 | -------------------------------------------------------------------------------- /rootfs/usr/local/bin/install-tools: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | set -e 3 | 4 | box() { 5 | local version="4.6.1" 6 | if [ "$PHP_VERSION" = "81" ]; then 7 | version="4.5.1" 8 | fi 9 | echo "Installing Box $version" 10 | wget -q "https://github.com/box-project/box/releases/download/$version/box.phar" -O /usr/local/bin/box 11 | chmod a+x /usr/local/bin/box 12 | } 13 | 14 | co_phpunit() { 15 | local version="3.1.3" 16 | echo "Installing co-phpunit $version" 17 | wget -q "https://raw.githubusercontent.com/hyperf/testing/v$version/co-phpunit" -O /usr/local/bin/co-phpunit 18 | chmod a+x /usr/local/bin/co-phpunit 19 | } 20 | 21 | composer() { 22 | local version="993f9fec74930f32f7015e71543243bf6d9b9e93" 23 | echo "Installing Composer $version" 24 | wget "https://raw.githubusercontent.com/composer/getcomposer.org/$version/web/installer" -O - -q | php -- --quiet 25 | mv composer.phar /usr/local/bin/composer 26 | chmod a+x /usr/local/bin/composer 27 | } 28 | 29 | composer_require_checker() { 30 | local version="4.10.0" 31 | if [ "$PHP_VERSION" = "81" ]; then 32 | version="4.7.1" 33 | fi 34 | echo "Installing ComposerRequireChecker $version" 35 | wget -q "https://github.com/maglnet/ComposerRequireChecker/releases/download/$version/composer-require-checker.phar" -O /usr/local/bin/composer-require-checker 36 | chmod a+x /usr/local/bin/composer-require-checker 37 | } 38 | 39 | couscous() { 40 | local version="1.10.0" 41 | echo "Installing Couscous $version" 42 | wget -q "https://github.com/CouscousPHP/Couscous/releases/download/$version/couscous.phar" -O /usr/local/bin/couscous 43 | chmod a+x /usr/local/bin/couscous 44 | } 45 | 46 | deptrac() { 47 | local version="1.0.2" 48 | echo "Installing Deptrac $version" 49 | wget -q "https://github.com/qossmic/deptrac/releases/download/$version/deptrac.phar" -O /usr/local/bin/deptrac 50 | chmod a+x /usr/local/bin/deptrac 51 | } 52 | 53 | exakat() { 54 | local version="2.6.2" 55 | echo "Installing Exakat $version" 56 | wget -q "https://www.exakat.io/versions/index.php?file=exakat-$version.phar" -O /usr/local/bin/exakat 57 | chmod a+x /usr/local/bin/exakat 58 | } 59 | 60 | infection() { 61 | local version="0.27.10" 62 | echo "Installing Infection $version" 63 | wget -q "https://github.com/infection/infection/releases/download/$version/infection.phar" -O /usr/local/bin/infection 64 | chmod a+x /usr/local/bin/infection 65 | } 66 | 67 | php_cs_fixer() { 68 | local version="3.51.0" 69 | echo "Installing PHP CS Fixer $version" 70 | wget -q "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/releases/download/v$version/php-cs-fixer.phar" -O /usr/local/bin/php-cs-fixer 71 | chmod a+x /usr/local/bin/php-cs-fixer 72 | } 73 | 74 | phpcbf() { 75 | local version="3.7.2" 76 | echo "Installing PHP CodeSniffer $version (phpcbf)" 77 | wget -q "https://github.com/squizlabs/PHP_CodeSniffer/releases/download/$version/phpcbf.phar" -O /usr/local/bin/phpcbf 78 | chmod a+x /usr/local/bin/phpcbf 79 | } 80 | 81 | phpcs() { 82 | local version="3.7.2" 83 | echo "Installing PHP CodeSniffer $version (phpcs)" 84 | wget -q "https://github.com/squizlabs/PHP_CodeSniffer/releases/download/$version/phpcs.phar" -O /usr/local/bin/phpcs 85 | chmod a+x /usr/local/bin/phpcs 86 | } 87 | 88 | phpmd() { 89 | local version="2.15.0" 90 | echo "Installing PHP Mess Detector $version" 91 | wget -q "https://github.com/phpmd/phpmd/releases/download/$version/phpmd.phar" -O /usr/local/bin/phpmd 92 | chmod a+x /usr/local/bin/phpmd 93 | } 94 | 95 | phpstan() { 96 | local version="1.10.59" 97 | echo "Installing PHPStan $version" 98 | wget -q "https://github.com/phpstan/phpstan/releases/download/$version/phpstan.phar" -O /usr/local/bin/phpstan 99 | chmod a+x /usr/local/bin/phpstan 100 | } 101 | 102 | phpunit() { 103 | local version="11" 104 | if [ "$PHP_VERSION" = "81" ]; then 105 | version="10" 106 | fi 107 | echo "Installing PHPUnit $version" 108 | wget -q "https://phar.phpunit.de/phpunit-$version.phar" -O /usr/local/bin/phpunit 109 | chmod a+x /usr/local/bin/phpunit 110 | } 111 | 112 | pint() { 113 | local version="1.14.0" 114 | echo "Installing Pint $version" 115 | wget -q "https://github.com/laravel/pint/releases/download/v$version/pint.phar" -O /usr/local/bin/pint 116 | chmod a+x /usr/local/bin/pint 117 | } 118 | 119 | psysh() { 120 | echo "Installing PsySH" 121 | wget -q https://psysh.org/psysh -O /usr/local/bin/psysh 122 | chmod a+x /usr/local/bin/psysh 123 | } 124 | 125 | watchr() { 126 | local version="0.5.3" 127 | echo "Installing watchr $version" 128 | wget -q "https://github.com/flavioheleno/watchr/releases/download/v$version/watchr.phar" -O /usr/local/bin/watchr 129 | chmod a+x /usr/local/bin/watchr 130 | } 131 | 132 | install() { 133 | box 134 | co_phpunit 135 | composer 136 | composer_require_checker 137 | couscous 138 | deptrac 139 | [ -n "$WITH_EXAKAT" ] && exakat 140 | infection 141 | php_cs_fixer 142 | phpcbf 143 | phpcs 144 | phpmd 145 | phpstan 146 | phpunit 147 | pint 148 | psysh 149 | [ -z "$WITHOUT_WATCHR" ] && watchr 150 | echo "Done!" 151 | } 152 | 153 | install 154 | -------------------------------------------------------------------------------- /scripts/symlink-bins.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | for file in "${1:-.}"/bin/*; do 3 | ln -sf "$(realpath "$file")" "/usr/local/bin/$(basename "$file")" 4 | done 5 | -------------------------------------------------------------------------------- /skeletons/.php-cs-fixer.php: -------------------------------------------------------------------------------- 1 | setRiskyAllowed(true) 23 | ->setRules([ 24 | '@PSR2' => true, 25 | '@Symfony' => true, 26 | '@DoctrineAnnotation' => true, 27 | '@PhpCsFixer' => true, 28 | 'header_comment' => [ 29 | 'comment_type' => 'PHPDoc', 30 | 'header' => $header, 31 | 'separate' => 'none', 32 | 'location' => 'after_declare_strict', 33 | ], 34 | 'array_syntax' => [ 35 | 'syntax' => 'short', 36 | ], 37 | 'list_syntax' => [ 38 | 'syntax' => 'short', 39 | ], 40 | 'concat_space' => [ 41 | 'spacing' => 'one', 42 | ], 43 | 'global_namespace_import' => [ 44 | 'import_classes' => true, 45 | 'import_constants' => true, 46 | 'import_functions' => null, 47 | ], 48 | 'blank_line_before_statement' => [ 49 | 'statements' => [ 50 | 'declare', 51 | ], 52 | ], 53 | 'general_phpdoc_annotation_remove' => [ 54 | 'annotations' => [ 55 | 'author', 56 | ], 57 | ], 58 | 'ordered_imports' => [ 59 | 'imports_order' => [ 60 | 'class', 'function', 'const', 61 | ], 62 | 'sort_algorithm' => 'alpha', 63 | ], 64 | 'single_line_comment_style' => [ 65 | 'comment_types' => [ 66 | ], 67 | ], 68 | 'yoda_style' => [ 69 | 'always_move_variable' => false, 70 | 'equal' => false, 71 | 'identical' => false, 72 | ], 73 | 'phpdoc_align' => [ 74 | 'align' => 'left', 75 | ], 76 | 'multiline_whitespace_before_semicolons' => [ 77 | 'strategy' => 'no_multi_line', 78 | ], 79 | 'constant_case' => [ 80 | 'case' => 'lower', 81 | ], 82 | 'class_attributes_separation' => true, 83 | 'combine_consecutive_unsets' => true, 84 | 'declare_strict_types' => true, 85 | 'linebreak_after_opening_tag' => true, 86 | 'lowercase_static_reference' => true, 87 | 'no_useless_else' => true, 88 | 'no_unused_imports' => true, 89 | 'not_operator_with_successor_space' => true, 90 | 'not_operator_with_space' => false, 91 | 'ordered_class_elements' => true, 92 | 'php_unit_strict' => false, 93 | 'phpdoc_separation' => false, 94 | 'single_quote' => true, 95 | 'standardize_not_equals' => true, 96 | 'multiline_comment_opening_closing' => true, 97 | 'single_line_empty_body' => false, 98 | ]) 99 | ->setFinder( 100 | PhpCsFixer\Finder::create() 101 | ->exclude('public') 102 | ->exclude('runtime') 103 | ->exclude('vendor') 104 | ->in(__DIR__) 105 | ) 106 | ->setUsingCache(true); 107 | -------------------------------------------------------------------------------- /skeletons/box.json: -------------------------------------------------------------------------------- 1 | { 2 | "chmod": "0700" 3 | } 4 | -------------------------------------------------------------------------------- /skeletons/infection.json5: -------------------------------------------------------------------------------- 1 | { 2 | "source": { 3 | "directories": ["src"] 4 | }, 5 | "timeout": 10, 6 | "logs": { 7 | "text": "infection.log" 8 | }, 9 | "mutators": {}, 10 | "testFramework": "phpunit", 11 | "bootstrap": "vendor/autoload.php", 12 | "minMsi": 0 13 | } 14 | -------------------------------------------------------------------------------- /skeletons/phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 9 3 | paths: 4 | - src 5 | reportUnmatchedIgnoredErrors: false 6 | ignoreErrors: 7 | # Magic behaviour with __get, __set, __call and __callStatic is not exactly static analyser-friendly :) 8 | # Fortunately, You can ignore it by the following config. 9 | - '#Static call to instance method Hyperf\\HttpServer\\Router\\Router::[a-zA-Z0-9\\_]+\(\)#' 10 | - '#Static call to instance method Hyperf\\DbConnection\\Db::[a-zA-Z0-9\\_]+\(\)#' 11 | -------------------------------------------------------------------------------- /skeletons/phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | tests 8 | 9 | 10 | 11 | 12 | 13 | src 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src-devc/.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG PHP_VERSION 83 2 | ARG PHP_VERSION_STR 8.3 3 | FROM php:${PHP_VERSION_STR}-cli-bookworm 4 | ENV PHP_VERSION $PHP_VERSION 5 | COPY rootfs / 6 | ADD --chmod=0755 https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/ 7 | RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 8 | && apt-get -y install --no-install-recommends libcurl4-openssl-dev libc-ares-dev libsqlite3-dev libpq-dev git parallel unzip wget libbrotli-dev \ 9 | && mv /usr/local/etc/php/php.ini-development /usr/local/etc/php/php.ini \ 10 | && mv /etc/php/php.ini /usr/local/etc/php/conf.d/zzphp.ini \ 11 | && install-php-extensions sockets && install-swoole && install-tools 12 | -------------------------------------------------------------------------------- /src-devc/.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": { 3 | "dockerfile": "./Dockerfile", 4 | "context": "../..", 5 | "args": { 6 | "PHP_VERSION": "${localEnv:PHP_VERSION}", 7 | "PHP_VERSION_STR": "${localEnv:PHP_VERSION_STR}" 8 | } 9 | }, 10 | "features": { 11 | "ghcr.io/devcontainers/features/common-utils:2": { 12 | "installZsh": "true", 13 | "username": "phpctl", 14 | "userUid": "1000", 15 | "userGid": "1000", 16 | "upgradePackages": "true" 17 | }, 18 | "ghcr.io/opencodeco/devcontainers/install-php-extensions:latest": { 19 | "extensions": "decimal gd intl mongodb pcntl pcov pdo_mysql pdo_pgsql rdkafka redis xdebug" 20 | } 21 | }, 22 | "overrideFeatureInstallOrder": [ 23 | "ghcr.io/devcontainers/features/common-utils" 24 | ], 25 | "remoteUser": "phpctl" 26 | } 27 | -------------------------------------------------------------------------------- /src-devc/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | export PHP_VERSION_STR="${PHP_VERSION:0:1}.${PHP_VERSION:1}" 3 | devcontainer build --workspace-folder src-devc --push true --image-name "opencodeco/phpctl:php$PHP_VERSION-devcontainer" 4 | -------------------------------------------------------------------------------- /src/bundle.sh: -------------------------------------------------------------------------------- 1 | bundle() { 2 | image="$1" 3 | alias="${image##*/}" 4 | alias="${2-$alias}" 5 | command="${3-index.php}" 6 | entrypoint="${4-php}" 7 | from="${5-opencodeco/phpctl:php82}" 8 | cp "$PHPCTL_DIR/bundle/Dockerfile" "$PHPCTL_DIR/bundle/docker-entrypoint.sh" . 9 | docker build \ 10 | --build-arg FROM="$from" \ 11 | --build-arg ENTRYPOINT="$entrypoint" \ 12 | --build-arg COMMAND="$command" \ 13 | -t "$image" . 14 | rm Dockerfile docker-entrypoint.sh 15 | cp "$PHPCTL_DIR/bundle/bin.sh" "$alias" 16 | sed -i.bak "s#IMAGE#$image#g" "$alias" 17 | rm "$alias.bak" 18 | chmod a+x "$alias" 19 | } 20 | -------------------------------------------------------------------------------- /src/docker.sh: -------------------------------------------------------------------------------- 1 | build() { 2 | local with_exakat="" 3 | if [[ "$*" == *--with-exakat* ]]; then 4 | with_exakat="--build-arg WITH_EXAKAT=1" 5 | fi 6 | 7 | local without_watchr="" 8 | if [[ "$*" == *--without-watchr* ]] || [ "$PHP_VERSION" = "81" ]; then 9 | without_watchr="--build-arg WITHOUT_WATCHR=1" 10 | fi 11 | 12 | echo -e "Building \033[0;32m$PHPCTL_IMAGE\033[0m" 13 | # shellcheck disable=SC2068 14 | # shellcheck disable=SC2154 15 | $PHPCTL_RUNTIME buildx build \ 16 | --build-arg PHP="$PHP_VERSION" \ 17 | --build-arg COMPOSER_AUTH="$COMPOSER_AUTH" \ 18 | --build-arg HOST_USER="$(whoami)" \ 19 | $with_exakat \ 20 | $without_watchr \ 21 | ${build[@]} -t "$PHPCTL_IMAGE" . 22 | } 23 | 24 | push() { 25 | echo -e "Pushing \033[0;32m$PHPCTL_IMAGE\033[0m" 26 | $PHPCTL_RUNTIME push "$PHPCTL_IMAGE" 27 | } 28 | 29 | pull() { 30 | echo -e "Pulling \033[0;32m$PHPCTL_IMAGE\033[0m" 31 | $PHPCTL_RUNTIME pull "$PHPCTL_IMAGE" 32 | } 33 | 34 | images() { 35 | $PHPCTL_RUNTIME images | grep phpctl 36 | } 37 | 38 | run() { 39 | if [ -n "$PHPCTL_VERBOSE" ]; then 40 | echo -e "Running \033[0;32m$PHPCTL_IMAGE\033[0m" 41 | fi 42 | 43 | local phpctl_ini="" 44 | if [ -s phpctl.ini ]; then 45 | phpctl_ini="-v $(pwd)/phpctl.ini:/etc/php$PHP_VERSION/conf.d/zzzphp.ini" 46 | fi 47 | 48 | local composer_home="" 49 | composer_home="$(composer-home)" 50 | if [ -n "$composer_home" ]; then 51 | composer_home="-v $composer_home:$composer_home" 52 | fi 53 | 54 | local gitconfig="" 55 | if [ -f ~/.gitconfig ]; then 56 | gitconfig="-v $HOME/.gitconfig:/root/.gitconfig:ro" 57 | fi 58 | 59 | if [ -n "$GIT_EXEC_PATH" ]; then 60 | # In a Git hook environment, we need to disable TTY allocation 61 | PHPCTL_TTY="--label=no-tty" 62 | fi 63 | 64 | # shellcheck disable=SC2046 65 | # shellcheck disable=SC2068 66 | # shellcheck disable=SC2086 67 | # shellcheck disable=SC2154 68 | $PHPCTL_RUNTIME run \ 69 | --init \ 70 | --platform linux/x86_64 \ 71 | --rm "$PHPCTL_TTY" \ 72 | --name "phpctl_$(openssl rand -hex 6)" \ 73 | --user "$PHPCTL_USER" \ 74 | $(env | awk -F= '/^[[:alpha:]]/{print $1}' | sed 's/^/-e/') \ 75 | -v /var/run/docker.sock:/var/run/docker.sock \ 76 | $gitconfig \ 77 | -v "$(pwd)":/usr/local/src -w /usr/local/src \ 78 | -v "$PHPCTL_DIR/php.ini:/etc/php$PHP_VERSION/conf.d/zphp.ini" \ 79 | $phpctl_ini \ 80 | $composer_home \ 81 | --net host --entrypoint sh \ 82 | ${args[@]} "$1" "$PHPCTL_IMAGE" -c "${*:2}" 83 | } 84 | -------------------------------------------------------------------------------- /src/doctor.sh: -------------------------------------------------------------------------------- 1 | doctor() { 2 | echo -e "PHP_VERSION=\033[0;32m$PHP_VERSION\033[0m" 3 | 4 | for var in $(set | awk -F= '/^[[:alpha:]]/{print $1}'); do 5 | if [[ $var == PHPCTL_* ]]; then 6 | echo -e "$var=\033[0;32m${!var}\033[0m" 7 | fi 8 | done 9 | } 10 | -------------------------------------------------------------------------------- /src/frankenphp.sh: -------------------------------------------------------------------------------- 1 | frankenphp() { 2 | if [ -z "$1" ]; then 3 | PHPCTL_IMAGE=opencodeco/phpctl:frankenphp run -- frankenphp run --config /etc/caddy/Caddyfile --adapter caddyfile 4 | else 5 | PHPCTL_IMAGE=opencodeco/phpctl:frankenphp run -- frankenphp "$@" 6 | fi 7 | } 8 | -------------------------------------------------------------------------------- /src/help.sh: -------------------------------------------------------------------------------- 1 | man() { 2 | help 3 | } 4 | 5 | list() { 6 | help 7 | } 8 | 9 | help() { 10 | echo -e " _ _ _ " 11 | echo -e " ___| |_ ___ ___| |_| |" 12 | echo -e "| . | | . | _| _| |" 13 | echo -e "| _|_|_| _|___|_| |_|" 14 | echo -e "|_| |_| " 15 | echo -e "$(doctor)" 16 | echo -e "" 17 | echo -e "\033[0;33mUsage:\033[0m " 18 | echo -e " phpctl [arguments] " 19 | echo -e "" 20 | echo -e "\033[0;33mAvailable commands:\033[0m" 21 | echo -e "\033[0;32m help or man \033[0m Displays this help message" 22 | echo -e "\033[0;32m php \033[0m Runs PHP commands" 23 | echo -e "\033[0;32m composer \033[0m Runs Composer commands" 24 | echo -e "\033[0;32m server [port] [directory] \033[0m Runs PHP's built-in web server (default port is 80 and default directory is current .)" 25 | echo -e "\033[0;32m sh [commands] \033[0m Starts an interactive Shell session or runs sh commands" 26 | echo -e "\033[0;32m repl \033[0m Starts a PHP REPL session (powered by PsySH)" 27 | echo -e "\033[0;32m bundle \033[0m Bundles a PHP project into a Docker image" 28 | echo -e "\033[0;32m create [framework] [dir] \033[0m Creates a new project using the given framework (or package)" 29 | echo -e "\033[0;32m init [skeleton] \033[0m Initializes a skeleton configuration (phpunit, php-cs-fixer)" 30 | echo -e "\033[0;32m self-update \033[0m Updates phpctl itself" 31 | echo -e "\033[0;32m doctor \033[0m Inspects the current PHP_VERSION and PHPCTL_IMAGE" 32 | echo -e "\033[0;32m build \033[0m Builds the current Dockerfile (useful for custom images)" 33 | echo -e "\033[0;32m images \033[0m Shows local phpctl images" 34 | echo -e "" 35 | echo -e "\033[0;33mTools:\033[0m" 36 | echo -e "\033[0;32m box \033[0m Runs Box (PHAR builder)" 37 | echo -e "\033[0;32m co-phpunit \033[0m Runs co-phpunit (Coroutine-aware PHPUnit for Hyperf)" 38 | echo -e "\033[0;32m composer-require-checker \033[0m Runs ComposerRequireChecker" 39 | echo -e "\033[0;32m couscous \033[0m Runs Couscous" 40 | echo -e "\033[0;32m deptrac \033[0m Runs Deptrac" 41 | echo -e "\033[0;32m exakat \033[0m Runs Exakat" 42 | echo -e "\033[0;32m frankenphp \033[0m Runs FrankenPHP" 43 | echo -e "\033[0;32m infection \033[0m Runs Infection, a PHP Mutation Testing Framework" 44 | echo -e "\033[0;32m pest \033[0m Runs Pest" 45 | echo -e "\033[0;32m php-cs-fixer \033[0m Runs PHP-CS-Fixer" 46 | echo -e "\033[0;32m phpcbf \033[0m Runs PHP_CodeSniffer (phpcbf)" 47 | echo -e "\033[0;32m phpcs \033[0m Runs PHP_CodeSniffer (phpcs)" 48 | echo -e "\033[0;32m phpmd \033[0m Runs PHP Mess Detector" 49 | echo -e "\033[0;32m phpstan \033[0m Runs PHPStan" 50 | echo -e "\033[0;32m phpunit \033[0m Runs PHPUnit" 51 | echo -e "\033[0;32m pint \033[0m Runs Pint" 52 | echo -e "\033[0;32m rector \033[0m Runs Rector" 53 | echo -e "\033[0;32m watchr \033[0m Runs watchr" 54 | echo -e "" 55 | } 56 | -------------------------------------------------------------------------------- /src/php.sh: -------------------------------------------------------------------------------- 1 | # shellcheck disable=SC2068 2 | 3 | php() { 4 | run -- php ${@--v} 5 | } 6 | 7 | composer() { 8 | if [ "$1" = "global" ]; then 9 | COMPOSER_HOME=$(composer-home) 10 | if [ -z "$COMPOSER_HOME" ]; then 11 | echo -e "\033[0;31mCOMPOSER_HOME not set.\033[0m" 12 | exit 1 13 | fi 14 | 15 | cd "$COMPOSER_HOME" || exit 1 16 | echo -e "\033[0;32mChanged current directory to $COMPOSER_HOME\033[0m" 17 | run -- composer ${@:2} 18 | else 19 | run -- composer ${@} 20 | fi 21 | } 22 | 23 | repl() { 24 | run -- psysh ${@} 25 | } 26 | 27 | server() { 28 | port=${1:-80} 29 | dir=${2:-.} 30 | run -- php -S 0.0.0.0:"$port" -t "$dir" 31 | } 32 | 33 | composer-home() { 34 | if [ -z "$COMPOSER_HOME" ]; then 35 | if [ -d ~/.config/composer ]; then 36 | COMPOSER_HOME="$HOME/.config/composer" 37 | elif [ -d ~/.composer ]; then 38 | COMPOSER_HOME="$HOME/.composer" 39 | fi 40 | fi 41 | 42 | echo "$COMPOSER_HOME" 43 | } 44 | -------------------------------------------------------------------------------- /src/scaffold.sh: -------------------------------------------------------------------------------- 1 | create() { 2 | package_alias="$1" 3 | case "$package_alias" in 4 | "hyperf") 5 | package="hyperf/hyperf-skeleton" 6 | ;; 7 | "laravel") 8 | package="laravel/laravel" 9 | ;; 10 | "symfony") 11 | package="symfony/skeleton" 12 | ;; 13 | *) 14 | package="$package_alias" 15 | ;; 16 | esac 17 | 18 | run -- composer create-project "$package" "$2" 19 | } 20 | 21 | init() { 22 | skeleton_alias="$1" 23 | case "$skeleton_alias" in 24 | "phpunit") 25 | skeleton="phpunit.xml" 26 | ;; 27 | "php-cs-fixer") 28 | skeleton=".php-cs-fixer.php" 29 | ;; 30 | "phpstan") 31 | skeleton="phpstan.neon" 32 | ;; 33 | "infection") 34 | skeleton="infection.json5" 35 | ;; 36 | "box") 37 | skeleton="box.json" 38 | ;; 39 | *) 40 | echo -e "\033[0;31mSkeleton ($skeleton_alias) not handled.\033[0m" 41 | exit 1 42 | esac 43 | 44 | cp "$PHPCTL_DIR/skeletons/$skeleton" "$skeleton" 45 | echo -e "\033[0;32m$skeleton created!\033[0m" 46 | } 47 | -------------------------------------------------------------------------------- /src/self-update.sh: -------------------------------------------------------------------------------- 1 | is_brew_installed() { 2 | command -v brew >/dev/null 2>&1 3 | } 4 | 5 | is_tap_installed() { 6 | local tap_name="$1" 7 | brew tap | grep -q "^$tap_name$" 8 | } 9 | 10 | self-update() { 11 | local tap_to_check="opencodeco/phpctl" 12 | local full_tap_pkg="$tap_to_check/phpctl" 13 | 14 | if is_brew_installed && is_tap_installed "$tap_to_check"; then 15 | echo -e "\033[32mSeems phpctl was installed by Homebrew, to update it run\033[0m brew upgrade $full_tap_pkg" 16 | else 17 | echo -e "Heading to \033[33m$PHPCTL_DIR\033[0m to update..." 18 | cd "$PHPCTL_DIR" || exit 1 19 | git pull origin HEAD 20 | echo -e "\033[32mUpdated!\033[0m" 21 | fi 22 | } 23 | -------------------------------------------------------------------------------- /src/sh.sh: -------------------------------------------------------------------------------- 1 | sh() { 2 | if [ -z "$1" ]; then 3 | run -- sh 4 | else 5 | run -- "$*" 6 | fi 7 | } 8 | -------------------------------------------------------------------------------- /src/tools.sh: -------------------------------------------------------------------------------- 1 | box() { 2 | if [ -f vendor/bin/box ]; then 3 | run -- vendor/bin/box ${@} 4 | else 5 | run -- box ${@} 6 | fi; 7 | } 8 | 9 | co-phpunit() { 10 | if [ -f vendor/bin/co-phpunit ]; then 11 | run -- vendor/bin/co-phpunit ${@} 12 | else 13 | run -- co-phpunit ${@} 14 | fi; 15 | } 16 | 17 | composer-require-checker() { 18 | run -- composer-require-checker ${@} 19 | } 20 | 21 | couscous() { 22 | if [ -f vendor/bin/couscous ]; then 23 | run -- vendor/bin/couscous ${@} 24 | else 25 | run -- couscous ${@} 26 | fi; 27 | } 28 | 29 | deptrac() { 30 | run -- deptrac ${@} 31 | } 32 | 33 | exakat() { 34 | if [ -f vendor/bin/exakat ]; then 35 | run -- vendor/bin/exakat ${@} 36 | else 37 | run -- exakat ${@} 38 | fi; 39 | } 40 | 41 | infection() { 42 | if [ -f vendor/bin/infection ]; then 43 | run -- vendor/bin/infection ${@} 44 | else 45 | run -- infection ${@} 46 | fi; 47 | } 48 | 49 | pest() { 50 | run -- vendor/bin/pest ${@} 51 | } 52 | 53 | php-cs-fixer() { 54 | if [ -f vendor/bin/php-cs-fixer ]; then 55 | run -- vendor/bin/php-cs-fixer ${@} 56 | else 57 | run -- php-cs-fixer ${@} 58 | fi; 59 | } 60 | 61 | phpcbf() { 62 | if [ -f vendor/bin/phpcbf ]; then 63 | run -- vendor/bin/phpcbf ${@} 64 | else 65 | run -- phpcbf ${@} 66 | fi; 67 | } 68 | 69 | phpcs() { 70 | if [ -f vendor/bin/phpcs ]; then 71 | run -- vendor/bin/phpcs ${@} 72 | else 73 | run -- phpcs ${@} 74 | fi; 75 | } 76 | 77 | phpmd() { 78 | if [ -f vendor/bin/phpmd ]; then 79 | run -- vendor/bin/phpmd ${@} 80 | else 81 | run -- phpmd ${@} 82 | fi; 83 | } 84 | 85 | phpstan() { 86 | if [ -f vendor/bin/phpstan ]; then 87 | run -- vendor/bin/phpstan ${@} 88 | else 89 | run -- phpstan ${@} 90 | fi; 91 | } 92 | 93 | phpunit() { 94 | if [ -f vendor/bin/phpunit ]; then 95 | run -- vendor/bin/phpunit ${@} 96 | else 97 | run -- phpunit ${@} 98 | fi; 99 | } 100 | 101 | pint() { 102 | if [ -f vendor/bin/pint ]; then 103 | run -- vendor/bin/pint ${@} 104 | else 105 | run -- pint ${@} 106 | fi; 107 | } 108 | 109 | rector() { 110 | run -- vendor/bin/rector ${@} 111 | } 112 | 113 | watchr() { 114 | run -- watchr ${@} 115 | } 116 | -------------------------------------------------------------------------------- /tests/doctor_test.sh: -------------------------------------------------------------------------------- 1 | function test_doctor() { 2 | assert_contains "PHPCTL_IMAGE=" "$(./bin/phpctl doctor)" 3 | } 4 | -------------------------------------------------------------------------------- /tests/help_test.sh: -------------------------------------------------------------------------------- 1 | function test_help_is_default() { 2 | assert_contains "phpctl [arguments]" "$(./bin/phpctl)" 3 | } 4 | -------------------------------------------------------------------------------- /tests/install/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build 2 | build: 3 | @parallel --line-buffer ./build {} ::: alpine archlinux ubuntu 4 | 5 | .PHONY: test 6 | test: 7 | @parallel --line-buffer ./test {} ::: alpine archlinux ubuntu 8 | -------------------------------------------------------------------------------- /tests/install/README.md: -------------------------------------------------------------------------------- 1 | This tests the `phpctl` installation in a blank Alpine distribution. 2 | 3 | Run `make OS=` then inside the container run `make install`. 4 | 5 | To check the installation, run `make test`. 6 | -------------------------------------------------------------------------------- /tests/install/alpine.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | RUN apk add bash curl docker git make neofetch openssl sudo 3 | COPY docker-entrypoint.sh / 4 | ENTRYPOINT ["/docker-entrypoint.sh"] 5 | -------------------------------------------------------------------------------- /tests/install/archlinux.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM archlinux 2 | RUN pacman -Syu --noconfirm curl docker git make neofetch sudo 3 | COPY docker-entrypoint.sh / 4 | ENTRYPOINT ["/docker-entrypoint.sh"] 5 | -------------------------------------------------------------------------------- /tests/install/build: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | echo -e "[$1] \033[0;32mBuilding...\033[0m" 3 | docker build -t "phpctl-$1-test" -f "$1.Dockerfile" . &> /dev/null 4 | echo -e "[$1] \033[0;32mDone!\033[0m" 5 | -------------------------------------------------------------------------------- /tests/install/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | neofetch 3 | /bin/bash -c "$(curl -fsSL https://phpctl.dev/install.sh)" 4 | echo "" 5 | notty phpctl doctor 6 | notty php --version 7 | notty composer --version 8 | -------------------------------------------------------------------------------- /tests/install/test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | echo -e "[$1] \033[0;32mTesting...\033[0m" 3 | echo -e "$(docker run --rm -v /var/run/docker.sock:/var/run/docker.sock "phpctl-$1-test")" 4 | -------------------------------------------------------------------------------- /tests/install/ubuntu.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu 2 | RUN apt update && apt install -y bash curl docker.io git make neofetch openssl sudo 3 | COPY docker-entrypoint.sh / 4 | ENTRYPOINT ["/docker-entrypoint.sh"] 5 | -------------------------------------------------------------------------------- /tests/php_test.sh: -------------------------------------------------------------------------------- 1 | function test_php_version_is_default() { 2 | assert_contains "Copyright (c) The PHP Group" "$(./bin/phpctl php)" 3 | } 4 | 5 | function test_php_accepts_arguments() { 6 | assert_contains "[PHP Modules]" "$(./bin/phpctl php -m)" 7 | assert_contains "Configuration File (php.ini) " "$(./bin/phpctl php --ini)" 8 | } 9 | 10 | function test_composer() { 11 | assert_contains "Composer version 2" "$(./bin/phpctl composer)" 12 | } 13 | 14 | function test_phpctl_ini() { 15 | echo "memory_limit=1337M" > phpctl.ini 16 | assert_contains "memory_limit => 1337M => 1337M" "$(./bin/phpctl php -i | grep memory_limit)" 17 | } 18 | -------------------------------------------------------------------------------- /tests/sh_test.sh: -------------------------------------------------------------------------------- 1 | function test_sh_commands() { 2 | assert_contains "/usr/local/src" "$(./bin/phpctl sh pwd)" 3 | assert_contains "test" "$(./bin/phpctl sh echo test)" 4 | } 5 | -------------------------------------------------------------------------------- /tests/tools_test.sh: -------------------------------------------------------------------------------- 1 | function test_box() { 2 | assert_matches "Box version 4\." "$(./bin/phpctl box --version)" 3 | } 4 | 5 | function test_co_phpunit() { 6 | assert_contains "Swoole\Coroutine\run" "$(./bin/phpctl sh cat /usr/local/bin/co-phpunit)" 7 | } 8 | 9 | function test_composer_require_checker() { 10 | assert_matches "ComposerRequireChecker 4\." "$(./bin/phpctl composer-require-checker --version)" 11 | } 12 | 13 | function test_couscous() { 14 | assert_matches "Couscous 1\." "$(./bin/phpctl couscous --version)" 15 | } 16 | 17 | function test_deptrac() { 18 | assert_matches "deptrac 1\." "$(./bin/phpctl deptrac --version)" 19 | } 20 | 21 | function test_exakat() { 22 | if [ -n "$WITH_EXAKAT" ]; then 23 | assert_matches "Version : 2\." "$(./bin/phpctl exakat version)" 24 | fi 25 | } 26 | 27 | function test_infection() { 28 | assert_matches "Infection - PHP Mutation Testing Framework version 0\.27\." "$(./bin/phpctl infection --version)" 29 | } 30 | 31 | function test_php_cs_fixer() { 32 | assert_matches "PHP CS Fixer 3\." "$(./bin/phpctl php-cs-fixer --version)" 33 | } 34 | 35 | function test_phpcbf() { 36 | assert_matches "PHP_CodeSniffer version 3\." "$(./bin/phpctl phpcbf --version)" 37 | } 38 | 39 | function test_phpcs() { 40 | assert_matches "PHP_CodeSniffer version 3\." "$(./bin/phpctl phpcs --version)" 41 | } 42 | 43 | function test_phpmd() { 44 | assert_matches "PHPMD 2\." "$(./bin/phpctl phpmd --version)" 45 | } 46 | 47 | function test_phpstan() { 48 | assert_matches "PHPStan - PHP Static Analysis Tool 1\." "$(./bin/phpctl phpstan --version)" 49 | } 50 | 51 | function test_phpunit() { 52 | if [ "$PHP_VERSION" = "81" ]; then 53 | assert_matches "PHPUnit 10\." "$(./bin/phpctl phpunit --version)" 54 | else 55 | assert_matches "PHPUnit 11\." "$(./bin/phpctl phpunit --version)" 56 | fi 57 | } 58 | 59 | function test_pint() { 60 | assert_matches "Pint 1\." "$(./bin/phpctl pint --version)" 61 | } 62 | 63 | function test_watchr() { 64 | if [ -z "$WITHOUT_WATCHR" ] && ! [ "$PHP_VERSION" = "81" ]; then 65 | assert_matches "watchr command-line utility v0\.5\." "$(./bin/phpctl watchr --version)" 66 | fi 67 | } 68 | --------------------------------------------------------------------------------