Skip to content

PHP versions

Butler can run several PHP versions side by side. You set one as the global default and override it per project whenever you need to.

Terminal window
butler use 8.3

Every site that hasn’t pinned its own version uses this one. You can also set the global version from the PHP section of the menu bar app.

If a version isn’t installed yet, add it:

Terminal window
butler install [email protected]

Installed versions appear in the app’s PHP section, where you can switch the default or install more with a click.

To run a single project on a different PHP version without changing your global default, run butler isolate from the project directory:

Terminal window
cd ~/Sites/my-app
butler isolate 8.2

Or target a site by name with --site from anywhere:

Terminal window
butler isolate 8.2 --site my-app

Now my-app.test uses PHP 8.2 while everything else stays on the default. Undo it with butler unisolate (also auto-detects from the current directory, or takes a site name):

Terminal window
butler unisolate my-app

You can also pin the version in the project’s butler.yml, which is handy because it travels with the repo:

php: "8.2"

A Valet-style .valetphprc (a file containing just 8.2) works too, so a project moved over from Valet keeps its pinned version without changing anything. butler.yml wins if a project has both.

butler php runs the active PHP for the current directory — the isolated version if the folder is a site with one pinned, otherwise your global default:

Terminal window
butler php -v
butler php artisan migrate

butler composer runs Composer through that same PHP, so your dependencies are resolved against the version the site actually uses:

Terminal window
butler composer install
butler composer require laravel/pint --dev

This matters more than it looks: Composer resolves platform requirements against the PHP it runs on, so resolving a site pinned to 8.1 with a global 8.4 writes a composer.lock the site can’t satisfy — usually noticed only when someone reaches for --ignore-platform-reqs.

Override it for one call with --php <ver>, or target another site from anywhere with --site <name>:

Terminal window
butler composer --php 8.4 require laravel/framework
butler composer --site my-app install

Global Composer tools (laravel, pint, pest) are the exception — they aren’t operating on the project you happen to be standing in, so they keep a predictable version: whatever butler composer-tools set <tool> <ver> pins, else the global default. Composer itself can’t be pinned that way, and butler composer-tools shows it as follows the site: a global pin would resolve every project’s dependencies against the wrong PHP, which is the problem per-site resolution exists to avoid.

This means you don’t have to juggle a system PHP or remember which version is on your PATH — Butler always uses the right one for where you are.

Every PHP version ships as a single static binary with a broad set of extensions compiled in — no pecl install, nothing to enable. This includes the ones a Laravel or general PHP app expects: pdo_mysql/pdo_pgsql/pdo_sqlite, mbstring (with mbregex), intl, gd and imagick, redis, mongodb, bcmath, gmp, sodium, openssl, curl, zip, readline (so php -a works), ffi, ldap, msgpack/igbinary, password-argon2 (Argon2id hashing), and more. Xdebug ships alongside as a load-on-demand extension — off by default, enabled per-invocation with XDEBUG_MODE (e.g. XDEBUG_MODE=debug butler php ...).

Both image extensions are built in — imagick links ImageMagick’s library statically into the PHP binary, so there’s no magick/convert CLI to install. Format support:

FormatImagickGD
JPEG / PNG / GIF
WebP
AVIF✅ read + write✅ read + write
HEIC / HEIFread only
JPEG XL, TIFF

HEIC (iPhone photos) can be decoded — so converting a .heic upload to WebP or JPEG works — but not written back out as HEIC. Everything else, including modern AVIF, is read/write on both extensions.

Butler ships each PHP version with an ini tuned for real frameworks (sensible memory limits, OPcache settings and so on). If you’ve edited a version’s php.ini and want to get back to Butler’s defaults, reset it from the PHP section of the app. Per-site PHP settings can also be set in butler.yml:

server:
phpSettings:
memory_limit: "1G"