Linux / Mac (php-unix):
-
Prerequisites: install Docker (Docker Desktop on Mac, or Docker Engine on Linux) and ensure the Docker daemon is running. On Mac, Colima + Docker also works.
-
Linux only: add your user to the
dockergroup so the wrapper can access Docker withoutsudo:sudo usermod -aG docker $USERThen log out and back in (or run
newgrp docker) for the group change to take effect. -
Copy the
php-unixfile to a directory on yourPATH, namedphp. Common destinations:-
Linux, or Intel Mac:
/usr/local/binsudo cp -i ~/your-download-location/php-unix /usr/local/bin/php -
Homebrew on Apple Silicon (if you use Homebrew):
/opt/homebrew/binsudo cp -i ~/your-download-location/php-unix /opt/homebrew/bin/php
-
-
Grant executable permissions:
sudo chmod +x /usr/local/bin/php -
Verify by running
php -v. The first run will pull the PHP container image; subsequent runs will show the PHP version. -
If you prefer Podman, replace
dockerwithpodmanin the script and ensure your Podman setup supports your OS.
Windows (php-windows.cmd):
-
Prerequisites: install Docker Desktop and ensure it's running, with the Linux containers backend enabled (the default).
-
Copy
php-windows.cmdto a directory on yourPATH, renamed tophp.cmd. For example, createC:\tools\phpand copy it there:mkdir C:\tools\php copy php-windows.cmd C:\tools\php\php.cmd
-
Add that directory to your
PATH(System Properties → Environment Variables, or from an elevated PowerShell prompt):setx PATH "%PATH%;C:\tools\php"
Then open a new terminal window for the change to take effect. (If you'd rather not risk
setxtruncating a longPATH, add the directory instead via System Properties → Environment Variables → Edit.) -
Verify by running
php -vfrom Command Prompt or PowerShell. The first run will pull the PHP container image; subsequent runs will show the PHP version. -
If
php -vfails with an image/platform error, Docker Desktop may be set to Windows containers instead of Linux containers (thephpimage is Linux-based). Right-click the Docker Desktop tray icon and choose Switch to Linux containers..., then try again.
Changing PHP versions:
The container used for this project comes from https://hub.docker.com/_/php. Edit the image tag (e.g. php:8.4.18-zts-alpine3.22) inside the wrapper script for your platform to change versions.
Uninstall / Remove
-
Remove the wrapper script:
- Linux/Mac:
sudo rm -f /usr/local/bin/php(or/opt/homebrew/bin/phpon Apple Silicon Homebrew installs) - Windows: delete
php.cmdfrom the directory you added toPATH(e.g.C:\tools\php)
- Linux/Mac:
-
Remove containers created from the
phpimage:The wrapper scripts run with
--rm, so containers are normally cleaned up automatically as soon as they exit. These commands only matter if one was killed abnormally (e.g. the host crashed mid-run) and got left behind.-
Stop running containers created from the
phpimage (if any):docker stop $(docker ps --filter ancestor=php:8.4.18-zts-alpine3.22 -q) -
Remove stopped containers created from the
phpimage:docker rm $(docker ps -a --filter ancestor=php:8.4.18-zts-alpine3.22 -q)
(The
ancestorfilter needs the fullimage:tag— a bareancestor=phpmatches nothing unless you're on the:latesttag, which this project doesn't use. Match the tag to whatever version you're actually running; see "Changing PHP versions" above. On Windows, run the equivalentdocker ps/docker stop/docker rmcommands directly, since$()command substitution isn't available in Command Prompt.) -
-
Remove the local
phpimage (optional):-
List
phpimages:docker images php -
Remove by name or ID:
docker rmi phpordocker rmi <IMAGE_ID>
-
-
Alternative (Podman): replace
dockerwithpodmanin the commands above. -
Quick cleanup (destructive):
- Remove all unused images, containers and networks (careful):
docker system prune -a
- Remove all unused images, containers and networks (careful):
These steps remove the wrapper script and any locally cached php container images/containers. Only run the image-removal commands if you know you no longer need the pulled PHP images.
Continuous Integration
.github/workflows/smoke-test.yml runs both wrapper scripts against the real php Docker image on every push and pull request — not just that they run, but that the $HOME/%USERPROFILE% and $PWD/%CD% mounts actually land where they're supposed to. The Linux job doubles as the closest available check for php-unix on Mac too, since GitHub-hosted macOS runners don't support Docker at all (no nested virtualization) — Mac itself isn't CI-tested.
The Windows job (php-windows.cmd) took a few iterations to get working, for reasons worth recording:
windows-latestrunners ship a Docker Engine defaulted to Windows containers, not Linux containers, so thephp(Linux/Alpine-based) image can't run until that's switched.- There's no Docker Desktop installed on that runner image to do the switch with — only the underlying Moby engine — so the fix is to install Docker Desktop in the job itself and wait for its Linux engine to come up before running anything.
- Once that was working, the job still failed — but the failure was in the test script, not the wrapper:
$out = & commandin PowerShell returns multi-line output as a string array, and-match/-notmatchagainst an array filters elements rather than returning a boolean. A "no line matches" result rendered as a non-empty (truthy) array, so the check false-failed even thoughphp -vhad printed the correct version. Fixed by joining the output to a single string before matching.