Installing PHP 8 on MacOS, Linux, and Windows with phpenv — The Hard Way (But Right)

Installing PHP 8 on MacOS, Linux, and Windows with phpenv — The Hard Way (But Right)
Photo by Ben Griffiths / Unsplash

You don’t install PHP manually on macOS unless you’re one of three things:

  • a developer,
  • someone building something reusable,
  • or a masochist with too much time.

In my case? All three.

This guide is the result of a battle-tested PHP 8.4.8 installation via phpenv on macOS, where we will patch, downgrade, link, unlink, modify, and manually whisper sweet nothings to configuration files until the PHP gods grant us a working setup.

Let’s go.


Step 0: The Environment

You're on a Mac (Apple Silicon in my case). You want to install PHP 8.4.8, possibly for a clean reproducible dev environment using phpenv, rather than cluttering your system PHP.

You also want to build a reusable PHP package (like php-multidispatch), and you want the environment stable and configurable.


Step 1: Install phpenv and php-build

brew install phpenv php-build

# OR clone manually if you want more control:
git clone https://github.com/phpenv/phpenv.git ~/.phpenv
echo 'export PATH="$HOME/.phpenv/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(phpenv init -)"' >> ~/.zshrc
source ~/.zshrc

# Install php-build plugin
git clone https://github.com/php-build/php-build.git ~/.phpenv/plugins/php-build

Verify:

phpenv --version

Step 2: Install the required libraries via Homebrew

To compile PHP from source, a bunch of headers and libraries are needed:

brew install \
  autoconf \
  bison \
  re2c \
  libxml2 \
  libjpeg \
  freetype \
  icu4c \
  libpng \
  libzip \
  oniguruma \
  bzip2 \
  libiconv \
  tidy-html5 \
  pkg-config

Ensure these environment variables are set (adapt paths if needed):

export CPPFLAGS="-I$(brew --prefix bzip2)/include -I$(brew --prefix libzip)/include -I$(brew --prefix libxml2)/include -I$(brew --prefix icu4c)/include"
export LDFLAGS="-L$(brew --prefix bzip2)/lib -L$(brew --prefix libzip)/lib -L$(brew --prefix libxml2)/lib -L$(brew --prefix icu4c)/lib"
export PKG_CONFIG_PATH="$(brew --prefix icu4c)/lib/pkgconfig:$(brew --prefix bzip2)/lib/pkgconfig"

Check:

echo $CPPFLAGS
echo $LDFLAGS

Step 3: Downgrade ICU if Needed

PHP 8.3 might fail to compile with newer icu4c. You can install an older version:

brew unlink icu4c
brew tap-new josephus/oldicu
brew extract --version=72 icu4c homebrew/core --tap=josephus/oldicu
brew install josephus/oldicu/icu4c@72
brew link --force --overwrite icu4c@72

export ICU_VERSION="72"
export ICU_PATH="$(brew --prefix icu4c@72)"
export CPPFLAGS="-I$ICU_PATH/include"
export LDFLAGS="-L$ICU_PATH/lib"
export PKG_CONFIG_PATH="$ICU_PATH/lib/pkgconfig"

Test:

pkg-config --modversion icu-uc
# Should return something like 72.1

Step 4: Edit the php-build Definition File

Create or edit the PHP version definition to include required options:

nano ~/.phpenv/plugins/php-build/share/php-build/definitions/8.4.8

Add these lines (you can copy/paste over the file if needed):

configure_option "--enable-gd"
configure_option "--with-jpeg"
configure_option "--with-zip"
configure_option "--with-mhash"
configure_option "--with-bz2=$(brew --prefix bzip2)"       # added manually
configure_option "--with-iconv=$(brew --prefix libiconv)"  # added manually
configure_option "--with-tidy=$(brew --prefix tidy-html5)" # added manually
configure_option -D "--with-xmlrpc"

export CXXFLAGS="-std=c++17"

install_package "https://www.php.net/distributions/php-8.4.8.tar.bz2"
install_xdebug "3.4.4"
enable_builtin_opcache

Step 5: Finally Install PHP 8.4.8

Clean up if a previous build failed:

rm -rf /var/tmp/php-build/source/8.4.8

Then install:

phpenv install 8.4.8

Set as default:

phpenv global 8.4.8

Test:

php --version

If you see PHP 8.4.8, you're done.


Bonus: Switch ICU Back If Needed

After the install, if other tools break due to ICU version, you can revert:

brew unlink icu4c@72
brew link --force icu4c

Appendix: Troubleshooting

  • Check logs under /tmp/php-build.*.log if anything fails.
  • Make sure you don’t have Conda or other bzip2/icu/libxml2 versions shadowing the Homebrew ones. conda deactivate might help.
  • Double-check pkg-config is pointing to Homebrew versions.

Linux (Ubuntu): Installing PHP with phpenv

The installation in Linux is very similar to the steps for MacOS:

1. Install Dependencies

sudo apt update
sudo apt install -y make build-essential libssl-dev \
  zlib1g-dev libbz2-dev libreadline-dev \
  libsqlite3-dev wget curl llvm \
  libncurses5-dev libncursesw5-dev \
  xz-utils tk-dev libxml2-dev libzip-dev \
  libjpeg-dev libpng-dev autoconf bison re2c

2. Install phpenv

git clone https://github.com/phpenv/phpenv.git ~/.phpenv
echo 'export PATH="$HOME/.phpenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(phpenv init -)"' >> ~/.bashrc
source ~/.bashrc

3. Install php-build Plugin

git clone https://github.com/php-build/php-build.git ~/.phpenv/plugins/php-build

4. Install PHP

phpenv install 8.4.8   # Or whichever version you want
phpenv global 8.4.8
php -v

5. Install Composer and PHPUnit

curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
composer --version

composer global require phpunit/phpunit
~/.composer/vendor/bin/phpunit --version

Windows: Installing PHP with phpenv via WSL

Note: phpenv does not run natively on Windows, but you can use it inside WSL (Windows Subsystem for Linux). On standard Windows, use Scoop or Chocolatey instead.

1. Install WSL & Ubuntu

Install WSL and Ubuntu from the Windows Store if you haven’t already.

wsl --install
# Or, from an admin PowerShell:
wsl --install -d Ubuntu

2. Open Ubuntu in WSL and Follow Linux Steps

Follow the exact same steps as above for Ubuntu:

  • Install dependencies
  • Clone phpenv
  • Install php-build
  • Install PHP versions
  • Set your desired PHP version as global

3. Composer & PHPUnit

Same as Linux:

curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
composer --version
composer global require phpunit/phpunit
~/.composer/vendor/bin/phpunit --version

Summary Table

Platform

phpenv Available?

Method

macOS

Yes

brew install phpenv php-build (see your article)

Linux (Ubuntu)

Yes

See steps above

Windows (native)

No

Use Scoop or Chocolatey

Windows (via WSL)

Yes

Use the Linux method inside WSL


Tip:

If you want simple prebuilt PHP on Windows, just use Scoop:

scoop install php composer phpunit

…but for advanced devs wanting multiple PHP versions and more control, use phpenv on Linux/macOS/WSL.

Final Words

Yes, this is not the easiest way. But it's the cleanest way to:

  • build your own PHP extensions,
  • maintain multiple versions side-by-side,
  • ensure reproducibility,
  • and understand exactly what your PHP installation is made of.

It’s pain now, freedom later.

Happy hacking!