13 KiB
13 KiB
paginate | footer |
---|---|
true | oliverdavies.uk |
Nix for PHP Developers
Oliver Davies (opdavies)
Nix for PHP Developers everyone
Oliver Davies (opdavies)
About Me
- PHP since 2007
- Drupal since 2008
- Full-time Linux since ~2015
- Nix/NixOS since 2022
- Gave my first presentation at unified.diff in September 2012
Who has PHP installed
on their computer?
Who has multiple versions
of PHP installed?
Installing PHP
- WAMP (Windows), MAMP (macOS), XAMPP
- Homebrew (
brew install php
) apt
,dnf
,yum
,pacman
yay
- Laravel Herd/Sail
- Symfony CLI?
- Containers (Docker, Podman, LXC, etc)
- Virtual machines (VMWare, Virtualbox, etc)
What is Nix?
- Package manager with more than 120,000 packages (
nixpkgs
) - Operating system with more than 20,000 packages (NixOS)
- Tool for declaratively building software reproducibly
- A functional domain-specific configuration language
- Home Manager,
nix-darwin
,devenv
- Started as a research project by Eelco Dolstra around 2003
What is Nix?
- Package manager
- Build tool
- Operating system
- Language
Installing Nix
$ sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) \
--daemon
Different instructions for Linux, macOS and Windows (WSL2).
Different instructions for NixOS.
$ nix --version
nix (Nix) 2.28.4
This installation tool will set up your computer with the Nix package
manager. This will happen in a few stages:
1. Make sure your computer doesn't already have Nix. If it does, I
will show you instructions on how to clean up your old install.
2. Show you what I am going to install and where. Then I will ask
if you are ready to continue.
3. Create the system users (uids [30001..30032]) and groups (gid 30000)
that the Nix daemon uses to run builds. To create system users
in a different range, exit and run this tool again with
NIX_FIRST_BUILD_UID set.
4. Perform the basic installation of the Nix files daemon.
5. Configure your shell to import special Nix Profile files, so you
can use Nix.
6. Start the Nix daemon.
Installing PHP with Ubuntu
$ apt update -y
$ apt-get install php
$ which php
/usr/bin/php
$ php -v
PHP 8.3.6
Running PHP with Nix
$ nix run nixpkgs#php -- -v
PHP 8.4.11
$ nix shell nixpkgs#php
$ which php
/nix/store/s4kv9bzqawhqcyjg9xm2hji3jap6d6kd-php-with-extensions-8.4.11/bin/php
$ php -v
PHP 8.4.11
Running PHP with Nix
$ nix run nixpkgs#php83 -- -v
PHP 8.3.25
$ nix run nixpkgs#php82 -- -v
PHP 8.2.29
Using a shell.nix
file
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
packages = with pkgs; [
php
phpPackages.composer
phpactor
];
}
$ nix-shell shell.nix
[nix-shell:~/my-project]$ composer -V
Composer version 2.8.5 2025-01-21 15:23:40
Using a flake.nix
file
{
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
outputs = inputs:
let
system = "x86_64-linux";
pkgs = import inputs.nixpkgs { inherit system; };
in {
devShells.${system}.default = (import ./shell.nix {
inherit pkgs;
});
};
}
Using a flake.nix
file
{
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
outputs = inputs:
let
system = "x86_64-linux";
pkgs = import inputs.nixpkgs { inherit system; };
in {
devShells.${system}.default = pkgs.mkShell {
packages = with pkgs; [
php
phpPackages.composer
phpactor
];
};
};
}
Structure of a Flake-based project
.
├── composer.json
├── composer.lock
├── flake.lock
├── flake.nix
├── output_dev
├── source
└── vendor
As well as flake.nix, we also get flake.lock.
Pinning packages
# flake.nix
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-24.11";
nixpkgs-pinned.url = "github:nixos/nixpkgs/45570c299dc2";
}
{
let
pkgs-stable = import inputs.nixpkgs-stable { inherit system; };
in {
packages = [ pkgs-stable.php ];
};
}
Managing services
With NixOS:
services.mysql.enable = true;
services.mysql.initialDatabases = [
{ name = "my_project"; }
{ name = "another_project"; }
];
Without NixOS:
https://github.com/juspay/services-flake
Managing services
{
inputs = {
flake-parts.url = "github:hercules-ci/flake-parts";
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
process-compose.url = "github:Platonic-Systems/process-compose-flake";
services.url = "github:juspay/services-flake";
};
# ...
Managing services
imports = [
inputs.process-compose.flakeModule
];
perSystem = { config, lib, pkgs, ... }: {
process-compose."default" = {
imports = [
inputs.services.processComposeModules.default
];
services = { # ... };
settings.processes = { # ... };
}
Managing services
services = {
mysql."mysql1" = {
enable = true;
initialDatabases = [
{ name = "drupal_nix_flake_example"; }
];
};
};
Managing services
settings.processes = {
php = {
command = pkgs.writeShellApplication {
name = "php-local-server";
text = "${getExe php} -S 127.0.0.1:${toString webPort} -t web";
};
depends_on."mysql1".condition = "process_healthy";
};
};
Managing services
devShells.default = pkgs.mkShell {
inputsFrom = [
config.process-compose."default".services.outputs.devShell
];
nativeBuildInputs = with pkgs; [
php
phpPackages.composer
];
};
};
Run nix run .
and go to http://localhost:8000.
Multiple PHPs
- Laravel Herd/Sail
- Containers
phpenv
,brew-php-switcher
,phpbrew
- Vagrant
- VMWare, VirtualBox
- Different physical machines?
Nix is like nvm
for everything
My ideal environment
$ php -v
The program 'php' is currently not installed.
$ cd ~/my-project
$ php -v
PHP 8.4.10
$ cd ~/another-project
$ php -v
PHP 8.3.24
Using direnv
It augments existing shells with a new feature that can load and unload environment variables depending on the current directory.
In NixOS:
{
programs.direnv.enable = true;
programs.direnv.nix-direnv.enable = true;
}
The .envrc file
If you have a flake.nix
:
use flake
Using a remote Flake:
use flake "git+https://code.oliverdavies.uk/opdavies/dev-shells#php84"
use flake "github:opdavies/dev-shells#php84"
Packaging for Nix
stdenv.mkDerivation (finalAttrs: {
pname = "hello";
version = "2.12.2";
src = fetchurl {
url = "mirror://gnu/hello/hello-${finalAttrs.version}.tar.gz";
hash = "sha256-WpqZbcKSzCTc9BHO6H6S9qrluNE72caBm0x6nc4IGKs=";
};
env = lib.optionalAttrs stdenv.hostPlatform.isDarwin {
NIX_LDFLAGS = "-liconv";
};
doCheck = true;
doInstallCheck = true;
# ...
Packaging for Nix
pkgs.writeShellApplication {
name = "preview";
runtimeInputs = with pkgs.nodePackages; [
browser-sync
];
text = ''
browser-sync start
--ignore '**/.*' \
--no-notify \
--no-ui \
-sw
'';
}
Packaging PHP for Nix
php.buildComposerProject2 (finalAttrs: {
pname = "phpactor";
version = "2025.07.25.0";
src = fetchFromGitHub {
owner = "phpactor";
repo = "phpactor";
tag = finalAttrs.version;
hash = "sha256-9XWlWwq+xvqPgKIc7IGoMVTxajjYsrPo/ra/0JIE168=";
};
vendorHash = "sha256-3xkt0QjytW4BOCgZdevat7zkSuZTPPvwz3yptiq5zoo=";
# ...
Packaging PHP for Nix
php.buildComposerProject2 (finalAttrs: {
pname = "pest";
version = "3.7.4";
src = fetchFromGitHub {
owner = "pestphp";
repo = "pest";
tag = "v${finalAttrs.version}";
hash = "sha256-ddsdVx/Vsg7GG11fGASouBU3HAJLSjs1AQGHx52TWzA=";
};
composerLock = ./composer.lock;
vendorHash = "sha256-rOJ6PFp4Xfe89usoH455EAT30d2Tu3zd3+C/6K/kGBw=";
# ...
Packaging Sculpin
Packaging Sculpin was essentially the same:
https://code.oliverdavies.uk/opdavies/lab/src/branch/main/nix/sculpin
nix build
./result/bin/sculpin generate
.
├── flake.lock
├── flake.nix
├── output_dev
│ └── index.html
└── source
└── index.md
Building Nix packages
$ nix repl
Nix 2.28.4
Type :? for help.
nix-repl> :l .
Added 24244 variables.
nix-repl> :b phpactor
This derivation produced the following outputs:
out -> /nix/store/nhq4js2lsj8lb1cz6dj4vrf6xb2r2zbd-phpactor-2025.03.28.0
/nix/store/nhq4js2lsj8lb1cz6dj4vrf6xb2r2zbd-phpactor-2025.03.28.0/bin/phpactor
Phpactor 2025.03.28.0
Not sure?
Want to try it, but you're not sure?
$ docker run --rm -it nixos/nix
$ podman run --rm -it nixos/nix
Thanks!
- https://nixos.org
- https://github.com/nixos/nixpkgs
- https://wiki.nixos.org/wiki/PHP
- https://nixos.org/manual/nixpkgs/stable/#ssec-building-php-projects
- https://code.oliverdavies.uk/opdavies/lab
- https://code.oliverdavies.uk/opdavies/nix-config (laptop and home server)
- https://books.oliverdavies.uk/nix-for-php-developers (book, in progress)