nixpkgs mirror (for testing) github.com/NixOS/nixpkgs
nix
at r-updates 339 lines 11 kB view raw view rendered
1# PHP {#sec-php} 2 3## User Guide {#ssec-php-user-guide} 4 5### Overview {#ssec-php-user-guide-overview} 6 7Several versions of PHP are available on Nix, each of which having a 8wide variety of extensions and libraries available. 9 10The different versions of PHP that nixpkgs provides are located under 11attributes named based on major and minor version number; e.g., 12`php84` is PHP 8.4. 13 14Only versions of PHP that are supported by upstream for the entirety 15of a given NixOS release will be included in that release of 16NixOS. See [PHP Supported 17Versions](https://www.php.net/supported-versions.php). 18 19The attribute `php` refers to the version of PHP considered most 20stable and thoroughly tested in nixpkgs for any given release of 21NixOS - not necessarily the latest major release from upstream. 22 23All available PHP attributes are wrappers around their respective 24binary PHP package and provide commonly used extensions this way. The 25real PHP 8.4 package, i.e. the unwrapped one, is available as 26`php84.unwrapped`; see the next section for more details. 27 28Interactive tools built on PHP are put in `php.packages`; composer is 29for example available at `php.packages.composer`. 30 31Most extensions that come with PHP, as well as some popular 32third-party ones, are available in `php.extensions`; for example, the 33opcache extension shipped with PHP is available at 34`php.extensions.opcache` and the third-party ImageMagick extension at 35`php.extensions.imagick`. 36 37### Installing PHP with extensions {#ssec-php-user-guide-installing-with-extensions} 38 39A PHP package with specific extensions enabled can be built using 40`php.withExtensions`. This is a function which accepts an anonymous 41function as its only argument; the function should accept two named 42parameters: `enabled` - a list of currently enabled extensions and 43`all` - the set of all extensions, and return a list of wanted 44extensions. For example, a PHP package with all default extensions and 45ImageMagick enabled: 46 47```nix 48php.withExtensions ({ enabled, all }: enabled ++ [ all.imagick ]) 49``` 50 51To exclude some, but not all, of the default extensions, you can 52filter the `enabled` list like this: 53 54```nix 55php.withExtensions ( 56 { enabled, all }: (lib.filter (e: e != php.extensions.opcache) enabled) ++ [ all.imagick ] 57) 58``` 59 60To build your list of extensions from the ground up, you can 61ignore `enabled`: 62 63```nix 64php.withExtensions ( 65 { all, ... }: 66 with all; 67 [ 68 imagick 69 opcache 70 ] 71) 72``` 73 74`php.withExtensions` provides extensions by wrapping a minimal php 75base package, providing a `php.ini` file listing all extensions to be 76loaded. You can access this package through the `php.unwrapped` 77attribute; useful if you, for example, need access to the `dev` 78output. The generated `php.ini` file can be accessed through the 79`php.phpIni` attribute. 80 81If you want a PHP build with extra configuration in the `php.ini` 82file, you can use `php.buildEnv`. This function takes two named and 83optional parameters: `extensions` and `extraConfig`. `extensions` 84takes an extension specification equivalent to that of 85`php.withExtensions`, `extraConfig` a string of additional `php.ini` 86configuration parameters. For example, a PHP package with the opcache 87and ImageMagick extensions enabled, and `memory_limit` set to `256M`: 88 89```nix 90php.buildEnv { 91 extensions = 92 { all, ... }: 93 with all; 94 [ 95 imagick 96 opcache 97 ]; 98 extraConfig = "memory_limit=256M"; 99} 100``` 101 102#### Example setup for `phpfpm` {#ssec-php-user-guide-installing-with-extensions-phpfpm} 103 104You can use the previous examples in a `phpfpm` pool called `foo` as 105follows: 106 107```nix 108let 109 myPhp = php.withExtensions ( 110 { all, ... }: 111 with all; 112 [ 113 imagick 114 opcache 115 ] 116 ); 117in 118{ 119 services.phpfpm.pools."foo".phpPackage = myPhp; 120} 121``` 122 123```nix 124let 125 myPhp = php.buildEnv { 126 extensions = 127 { all, ... }: 128 with all; 129 [ 130 imagick 131 opcache 132 ]; 133 extraConfig = "memory_limit=256M"; 134 }; 135in 136{ 137 services.phpfpm.pools."foo".phpPackage = myPhp; 138} 139``` 140 141#### Example usage with `nix-shell` {#ssec-php-user-guide-installing-with-extensions-nix-shell} 142 143This brings up a temporary environment that contains a PHP interpreter 144with the extensions `imagick` and `opcache` enabled: 145 146```sh 147nix-shell -p 'php.withExtensions ({ all, ... }: with all; [ imagick opcache ])' 148``` 149 150### Installing PHP packages with extensions {#ssec-php-user-guide-installing-packages-with-extensions} 151 152All interactive tools use the PHP package you get them from, so all 153packages at `php.packages.*` use the `php` package with its default 154extensions. Sometimes this default set of extensions isn't enough and 155you may want to extend it. A common case of this is the `composer` 156package: a project may depend on certain extensions and `composer` 157won't work with that project unless those extensions are loaded. 158 159Example of building `composer` with additional extensions: 160 161```nix 162(php.withExtensions ( 163 { all, enabled }: 164 enabled 165 ++ (with all; [ 166 imagick 167 redis 168 ]) 169)).packages.composer 170``` 171 172### Overriding PHP packages {#ssec-php-user-guide-overriding-packages} 173 174`php-packages.nix` form a scope, allowing us to override the packages defined 175within. For example, to apply a patch to a `mysqlnd` extension, you can 176pass an overlay-style function to `php`’s `packageOverrides` argument: 177 178```nix 179php.override { 180 packageOverrides = final: prev: { 181 extensions = prev.extensions // { 182 mysqlnd = prev.extensions.mysqlnd.overrideAttrs (attrs: { 183 patches = attrs.patches or [ ] ++ [ 184 # ... 185 ]; 186 }); 187 }; 188 }; 189} 190``` 191 192### Building PHP projects {#ssec-building-php-projects} 193 194With [Composer](https://getcomposer.org/), you can effectively build PHP 195projects by streamlining dependency management. As the de-facto standard 196dependency manager for PHP, Composer enables you to declare and manage the 197libraries your project relies on, ensuring a more organized and efficient 198development process. 199 200Composer is not a package manager in the same sense as `Yum` or `Apt` are. Yes, 201it deals with "packages" or libraries, but it manages them on a per-project 202basis, installing them in a directory (e.g. `vendor`) inside your project. By 203default, it does not install anything globally. This idea is not new and 204Composer is strongly inspired by Node's `npm` and Ruby's `bundler`. 205 206Currently, there is no other PHP tool that offers the same functionality as 207Composer. Consequently, incorporating a helper in Nix to facilitate building 208such applications is a logical choice. 209 210In a Composer project, dependencies are defined in a `composer.json` file, 211while their specific versions are locked in a `composer.lock` file. Some 212Composer-based projects opt to include this `composer.lock` file in their source 213code, while others choose not to. 214 215In Nix, there are multiple approaches to building a Composer-based project. 216 217::: {.warning} 218`buildComposerProject2` has a [known bug](https://github.com/NixOS/nixpkgs/issues/451395) 219where the `vendorHash` changes every time a Composer release happens that changes the 220`autoload.php` or vendored composer code. 221::: 222 223One such method is the `php.buildComposerProject2` helper function, which serves 224as a wrapper around `mkDerivation`. 225 226Using this function, you can build a PHP project that includes both a 227`composer.json` and `composer.lock` file. If the project specifies binaries 228using the `bin` attribute in `composer.json`, these binaries will be 229automatically linked and made accessible in the derivation. In this context, 230"binaries" refer to PHP scripts that are intended to be executable. 231 232To use the helper effectively, add the `vendorHash` attribute, which 233enables the wrapper to handle the heavy lifting. 234 235Internally, the helper operates in three stages: 236 2371. It constructs a `composerRepository` attribute derivation by creating a 238 composer repository on the filesystem containing dependencies specified in 239 `composer.json`. This process uses the function 240 `php.mkComposerRepository` which in turn uses the 241 `php.composerHooks.composerRepositoryHook` hook. Internally this function uses 242 a custom 243 [Composer plugin](https://github.com/nix-community/composer-local-repo-plugin) to 244 generate the repository. 2452. The resulting `composerRepository` derivation is then used by the 246 `php.composerHooks.composerInstallHook` hook, which is responsible for 247 creating the final `vendor` directory. 2483. Any "binary" specified in the `composer.json` are linked and made accessible 249 in the derivation. 250 251As the autoloader optimization can be activated directly within the 252`composer.json` file, we do not enable any autoloader optimization flags. 253 254To customize the PHP version, you can specify the `php` attribute. Similarly, if 255you wish to modify the Composer version, use the `composer` attribute. It is 256important to note that both attributes should be of the `derivation` type. 257 258Here's an example of working code example using `php.buildComposerProject2`: 259 260```nix 261{ php, fetchFromGitHub }: 262 263php.buildComposerProject2 (finalAttrs: { 264 pname = "php-app"; 265 version = "1.0.0"; 266 267 src = fetchFromGitHub { 268 owner = "git-owner"; 269 repo = "git-repo"; 270 tag = finalAttrs.version; 271 hash = "sha256-VcQRSss2dssfkJ+iUb5qT+FJ10GHiFDzySigcmuVI+8="; 272 }; 273 274 # PHP version containing the `ast` extension enabled 275 php = php.buildEnv { 276 extensions = ({ enabled, all }: enabled ++ (with all; [ ast ])); 277 }; 278 279 # The composer vendor hash 280 vendorHash = "sha256-86s/F+/5cBAwBqZ2yaGRM5rTGLmou5//aLRK5SA0WiQ="; 281 282 # If the composer.lock file is missing from the repository, add it: 283 # composerLock = ./path/to/composer.lock; 284}) 285``` 286 287In case the file `composer.lock` is missing from the repository, it is possible 288to specify it using the `composerLock` attribute. 289 290The other method is to use all these methods and hooks individually. This has 291the advantage of building a PHP library within another derivation very easily 292when necessary. 293 294Here's a working code example to build a PHP library using `mkDerivation` and 295separate functions and hooks: 296 297```nix 298{ 299 stdenvNoCC, 300 fetchFromGitHub, 301 php, 302}: 303 304stdenvNoCC.mkDerivation ( 305 finalAttrs: 306 let 307 src = fetchFromGitHub { 308 owner = "git-owner"; 309 repo = "git-repo"; 310 tag = finalAttrs.version; 311 hash = "sha256-VcQRSss2dssfkJ+iUb5qT+FJ10GHiFDzySigcmuVI+8="; 312 }; 313 in 314 { 315 inherit src; 316 pname = "php-app"; 317 version = "1.0.0"; 318 319 buildInputs = [ php ]; 320 321 nativeBuildInputs = [ 322 php.packages.composer 323 # This hook will use the attribute `composerRepository` 324 php.composerHooks.composerInstallHook 325 ]; 326 327 composerRepository = php.mkComposerRepository { 328 inherit (finalAttrs) pname version src; 329 composerNoDev = true; 330 composerNoPlugins = true; 331 composerNoScripts = true; 332 # Specifying a custom composer.lock since it is not present in the sources. 333 composerLock = ./composer.lock; 334 # The composer vendor hash 335 vendorHash = "sha256-86s/F+/5cBAwBqZ2yaGRM5rTGLmou5//aLRK5SA0WiQ="; 336 }; 337 } 338) 339```