about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/languages-frameworks/php.section.md75
-rw-r--r--nixos/doc/manual/release-notes/rl-2009.xml100
-rw-r--r--nixos/modules/services/mail/roundcube.nix2
-rw-r--r--nixos/modules/services/web-apps/nextcloud.nix4
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/default.nix2
-rw-r--r--pkgs/development/interpreters/php/default.nix473
-rw-r--r--pkgs/servers/http/unit/default.nix24
-rw-r--r--pkgs/servers/uwsgi/default.nix4
-rw-r--r--pkgs/top-level/aliases.nix48
-rw-r--r--pkgs/top-level/all-packages.nix4
-rw-r--r--pkgs/top-level/php-packages.nix25
11 files changed, 402 insertions, 359 deletions
diff --git a/doc/languages-frameworks/php.section.md b/doc/languages-frameworks/php.section.md
index a302a9a7f87d..101f7b043fff 100644
--- a/doc/languages-frameworks/php.section.md
+++ b/doc/languages-frameworks/php.section.md
@@ -9,18 +9,24 @@
 Several versions of PHP are available on Nix, each of which having a
 wide variety of extensions and libraries available.
 
-The attribute `php` refers to the version of PHP considered most
-stable and thoroughly tested in nixpkgs for any given release of
-NixOS. Note that while this version of PHP may not be the latest major
-release from upstream, any version of PHP supported in nixpkgs may be
-utilized by specifying the desired attribute by version, such as
-`php74`.
+The different versions of PHP that nixpkgs provides are located under
+attributes named based on major and minor version number; e.g.,
+`php74` is PHP 7.4.
 
 Only versions of PHP that are supported by upstream for the entirety
 of a given NixOS release will be included in that release of
 NixOS. See [PHP Supported
 Versions](https://www.php.net/supported-versions.php).
 
+The attribute `php` refers to the version of PHP considered most
+stable and thoroughly tested in nixpkgs for any given release of
+NixOS - not necessarily the latest major release from upstream.
+
+All available PHP attributes are wrappers around their respective
+binary PHP package and provide commonly used extensions this way. The
+real PHP 7.4 package, i.e. the unwrapped one, is available as
+`php74.unwrapped`; see the next section for more details.
+
 Interactive tools built on PHP are put in `php.packages`; composer is
 for example available at `php.packages.composer`.
 
@@ -30,39 +36,44 @@ opcache extension shipped with PHP is available at
 `php.extensions.opcache` and the third-party ImageMagick extension at
 `php.extensions.imagick`.
 
-The different versions of PHP that nixpkgs provides is located under
-attributes named based on major and minor version number; e.g.,
-`php74` is PHP 7.4 with commonly used extensions installed,
-`php74base` is the same PHP runtime without extensions.
-
-#### Installing PHP with packages
+#### Installing PHP with extensions
 
 A PHP package with specific extensions enabled can be built using
 `php.withExtensions`. This is a function which accepts an anonymous
-function as its only argument; the function should take one argument,
-the set of all extensions, and return a list of wanted extensions. For
-example, a PHP package with the opcache and ImageMagick extensions
-enabled:
+function as its only argument; the function should accept two named
+parameters: `enabled` - a list of currently enabled extensions and
+`all` - the set of all extensions, and return a list of wanted
+extensions. For example, a PHP package with all default extensions and
+ImageMagick enabled:
 
 ```nix
-php.withExtensions (e: with e; [ imagick opcache ])
+php.withExtensions ({ enabled, all }:
+  enabled ++ [ all.imagick ])
 ```
 
-Note that this will give you a package with _only_ opcache and
-ImageMagick, none of the other extensions which are enabled by default
-in the `php` package will be available.
+To exclude some, but not all, of the default extensions, you can
+filter the `enabled` list like this:
+
+```nix
+php.withExtensions ({ enabled, all }:
+  (lib.filter (e: e != php.extensions.opcache) enabled)
+  ++ [ all.imagick ])
+```
 
-To enable building on a previous PHP package, the currently enabled
-extensions are made available in its `enabledExtensions`
-attribute. For example, to generate a package with all default
-extensions enabled, except opcache, but with ImageMagick:
+To build your list of extensions from the ground up, you can simply
+ignore `enabled`:
 
 ```nix
-php.withExtensions (e:
-  (lib.filter (e: e != php.extensions.opcache) php.enabledExtensions)
-  ++ [ e.imagick ])
+php.withExtensions ({ all, ... }: with all; [ opcache imagick ])
 ```
 
+`php.withExtensions` provides extensions by wrapping a minimal php
+base package, providing a `php.ini` file listing all extensions to be
+loaded. You can access this package through the `php.unwrapped`
+attribute; useful if you, for example, need access to the `dev`
+output. The generated `php.ini` file can be accessed through the
+`php.phpIni` attribute.
+
 If you want a PHP build with extra configuration in the `php.ini`
 file, you can use `php.buildEnv`. This function takes two named and
 optional parameters: `extensions` and `extraConfig`. `extensions`
@@ -73,7 +84,7 @@ and ImageMagick extensions enabled, and `memory_limit` set to `256M`:
 
 ```nix
 php.buildEnv {
-  extensions = e: with e; [ imagick opcache ];
+  extensions = { all, ... }: with all; [ imagick opcache ];
   extraConfig = "memory_limit=256M";
 }
 ```
@@ -85,7 +96,7 @@ follows:
 
 ```nix
 let
-  myPhp = php.withExtensions (e: with e; [ imagick opcache ]);
+  myPhp = php.withExtensions ({ all, ... }: with all; [ opcache imagick ]);
 in {
   services.phpfpm.pools."foo".phpPackage = myPhp;
 };
@@ -94,7 +105,7 @@ in {
 ```nix
 let
   myPhp = php.buildEnv {
-    extensions = e: with e; [ imagick opcache ];
+    extensions = { all, ... }: with all; [ imagick opcache ];
     extraConfig = "memory_limit=256M";
   };
 in {
@@ -105,8 +116,8 @@ in {
 ##### Example usage with `nix-shell`
 
 This brings up a temporary environment that contains a PHP interpreter
-with the extensions `imagick` and `opcache` enabled.
+with the extensions `imagick` and `opcache` enabled:
 
 ```sh
-nix-shell -p 'php.buildEnv { extensions = e: with e; [ imagick opcache ]; }'
+nix-shell -p 'php.withExtensions ({ all, ... }: with all; [ imagick opcache ])'
 ```
diff --git a/nixos/doc/manual/release-notes/rl-2009.xml b/nixos/doc/manual/release-notes/rl-2009.xml
index 1cf7c977eeb0..e380e65ea7c6 100644
--- a/nixos/doc/manual/release-notes/rl-2009.xml
+++ b/nixos/doc/manual/release-notes/rl-2009.xml
@@ -145,69 +145,69 @@
    </listitem>
    <listitem>
      <para>
-       Since this release there's an easy way to customize your PHP install to get a much smaller
-       base PHP with only wanted extensions enabled. See the following snippet installing a smaller PHP
-       with the extensions <literal>imagick</literal>, <literal>opcache</literal> and
+       Since this release there's an easy way to customize your PHP
+       install to get a much smaller base PHP with only wanted
+       extensions enabled. See the following snippet installing a
+       smaller PHP with the extensions <literal>imagick</literal>,
+       <literal>opcache</literal>, <literal>pdo</literal> and
        <literal>pdo_mysql</literal> loaded:
 
        <programlisting>
 environment.systemPackages = [
-(pkgs.php.buildEnv { extensions = pp: with pp; [
-    imagick
-    opcache
-    pdo_mysql
-  ]; })
+  (pkgs.php.withExtensions
+    ({ all, ... }: with all; [
+      imagick
+      opcache
+      pdo
+      pdo_mysql
+    ])
+  )
 ];</programlisting>
 
-       The default <literal>php</literal> attribute hasn't lost any extensions -
-       the <literal>opcache</literal> extension was added there.
+       The default <literal>php</literal> attribute hasn't lost any
+       extensions. The <literal>opcache</literal> extension has been
+       added.
 
        All upstream PHP extensions are available under <package><![CDATA[php.extensions.<name?>]]></package>.
      </para>
      <para>
-       The updated <literal>php</literal> attribute is now easily customizable to your liking
-       by using extensions instead of writing config files or changing configure flags.
-
-       Therefore we have removed the following configure flags:
+       All PHP <literal>config</literal> flags have been removed for
+       the following reasons:
 
        <itemizedlist>
-         <title>PHP <literal>config</literal> flags that we don't read anymore:</title>
-         <listitem><para><literal>config.php.argon2</literal></para></listitem>
-         <listitem><para><literal>config.php.bcmath</literal></para></listitem>
-         <listitem><para><literal>config.php.bz2</literal></para></listitem>
-         <listitem><para><literal>config.php.calendar</literal></para></listitem>
-         <listitem><para><literal>config.php.curl</literal></para></listitem>
-         <listitem><para><literal>config.php.exif</literal></para></listitem>
-         <listitem><para><literal>config.php.ftp</literal></para></listitem>
-         <listitem><para><literal>config.php.gd</literal></para></listitem>
-         <listitem><para><literal>config.php.gettext</literal></para></listitem>
-         <listitem><para><literal>config.php.gmp</literal></para></listitem>
-         <listitem><para><literal>config.php.imap</literal></para></listitem>
-         <listitem><para><literal>config.php.intl</literal></para></listitem>
-         <listitem><para><literal>config.php.ldap</literal></para></listitem>
-         <listitem><para><literal>config.php.libxml2</literal></para></listitem>
-         <listitem><para><literal>config.php.libzip</literal></para></listitem>
-         <listitem><para><literal>config.php.mbstring</literal></para></listitem>
-         <listitem><para><literal>config.php.mysqli</literal></para></listitem>
-         <listitem><para><literal>config.php.mysqlnd</literal></para></listitem>
-         <listitem><para><literal>config.php.openssl</literal></para></listitem>
-         <listitem><para><literal>config.php.pcntl</literal></para></listitem>
-         <listitem><para><literal>config.php.pdo_mysql</literal></para></listitem>
-         <listitem><para><literal>config.php.pdo_odbc</literal></para></listitem>
-         <listitem><para><literal>config.php.pdo_pgsql</literal></para></listitem>
-         <listitem><para><literal>config.php.phpdbg</literal></para></listitem>
-         <listitem><para><literal>config.php.postgresql</literal></para></listitem>
-         <listitem><para><literal>config.php.readline</literal></para></listitem>
-         <listitem><para><literal>config.php.soap</literal></para></listitem>
-         <listitem><para><literal>config.php.sockets</literal></para></listitem>
-         <listitem><para><literal>config.php.sodium</literal></para></listitem>
-         <listitem><para><literal>config.php.sqlite</literal></para></listitem>
-         <listitem><para><literal>config.php.tidy</literal></para></listitem>
-         <listitem><para><literal>config.php.xmlrpc</literal></para></listitem>
-         <listitem><para><literal>config.php.xsl</literal></para></listitem>
-         <listitem><para><literal>config.php.zip</literal></para></listitem>
-         <listitem><para><literal>config.php.zlib</literal></para></listitem>
+         <listitem>
+           <para>
+             The updated <literal>php</literal> attribute is now easily
+             customizable to your liking by using
+             <literal>php.withExtensions</literal> or
+             <literal>php.buildEnv</literal> instead of writing config files
+             or changing configure flags.             
+           </para>
+         </listitem>
+         <listitem>
+           <para>
+             The remaining configuration flags can now be set directly on
+             the <literal>php</literal> attribute. For example, instead of 
+
+             <programlisting>
+php.override {
+  config.php.embed = true;
+  config.php.apxs2 = false;
+}
+             </programlisting>
+
+             you should now write
+
+             <programlisting>
+php.override {
+  embedSupport = true;
+  apxs2Support = false;
+}
+             </programlisting>
+           </para>
+         </listitem>
        </itemizedlist>
+
      </para>
    </listitem>
    <listitem>
diff --git a/nixos/modules/services/mail/roundcube.nix b/nixos/modules/services/mail/roundcube.nix
index 21e92cfee016..ed1439745ac9 100644
--- a/nixos/modules/services/mail/roundcube.nix
+++ b/nixos/modules/services/mail/roundcube.nix
@@ -7,7 +7,7 @@ let
   fpm = config.services.phpfpm.pools.roundcube;
   localDB = cfg.database.host == "localhost";
   user = cfg.database.username;
-  phpWithPspell = pkgs.php.withExtensions (e: [ e.pspell ] ++ pkgs.php.enabledExtensions);
+  phpWithPspell = pkgs.php.withExtensions ({ enabled, all }: [ all.pspell ] ++ enabled);
 in
 {
   options.services.roundcube = {
diff --git a/nixos/modules/services/web-apps/nextcloud.nix b/nixos/modules/services/web-apps/nextcloud.nix
index 5f6f2bc7a16d..f826096bf608 100644
--- a/nixos/modules/services/web-apps/nextcloud.nix
+++ b/nixos/modules/services/web-apps/nextcloud.nix
@@ -11,8 +11,8 @@ let
       base = pkgs.php74;
     in
       base.buildEnv {
-        extensions = e: with e;
-          base.enabledExtensions ++ [
+        extensions = { enabled, all }: with all;
+          enabled ++ [
             apcu redis memcached imagick
           ];
         extraConfig = phpOptionsStr;
diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix
index 653c17068346..8abee7130d7c 100644
--- a/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -338,7 +338,7 @@ let
     }
     ''
       cat ${php}/etc/php.ini > $out
-      cat ${php}/lib/custom-php.ini > $out
+      cat ${php.phpIni} > $out
       echo "$options" >> $out
     '';
 
diff --git a/pkgs/development/interpreters/php/default.nix b/pkgs/development/interpreters/php/default.nix
index 1d6576b383cd..4c79691f504c 100644
--- a/pkgs/development/interpreters/php/default.nix
+++ b/pkgs/development/interpreters/php/default.nix
@@ -1,250 +1,279 @@
 # We have tests for PCRE and PHP-FPM in nixos/tests/php/ or
 # both in the same attribute named nixosTests.php
 
-{ callPackage, config, fetchurl, lib, makeWrapper, stdenv, symlinkJoin
-, writeText , autoconf, automake, bison, flex, libtool, pkgconfig, re2c
-, apacheHttpd, libargon2, libxml2, pcre, pcre2 , systemd, valgrind
-}:
+{ callPackage, lib, stdenv, nixosTests }@_args:
 
 let
   generic =
-  { version
-  , sha256
-  , extraPatches ? []
-
-  # Sapi flags
-  , cgiSupport ? config.php.cgi or true
-  , cliSupport ? config.php.cli or true
-  , fpmSupport ? config.php.fpm or true
-  , pearSupport ? config.php.pear or true
-  , pharSupport ? config.php.phar or true
-  , phpdbgSupport ? config.php.phpdbg or true
-
-
-  # Misc flags
-  , apxs2Support ? config.php.apxs2 or (!stdenv.isDarwin)
-  , argon2Support ? config.php.argon2 or true
-  , cgotoSupport ? config.php.cgoto or false
-  , embedSupport ? config.php.embed or false
-  , ipv6Support ? config.php.ipv6 or true
-  , systemdSupport ? config.php.systemd or stdenv.isLinux
-  , valgrindSupport ? config.php.valgrind or true
-  , ztsSupport ? (config.php.zts or false) || (apxs2Support)
-  }: let
-    pcre' = if (lib.versionAtLeast version "7.3") then pcre2 else pcre;
-  in stdenv.mkDerivation {
-    pname = "php";
-
-    inherit version;
-
-    enableParallelBuilding = true;
-
-    nativeBuildInputs = [ autoconf automake bison flex libtool pkgconfig re2c ];
-
-    buildInputs =
-      # PCRE extension
-      [ pcre' ]
-
-      # Enable sapis
-      ++ lib.optional pearSupport [ libxml2.dev ]
-
-      # Misc deps
-      ++ lib.optional apxs2Support apacheHttpd
-      ++ lib.optional argon2Support libargon2
-      ++ lib.optional systemdSupport systemd
-      ++ lib.optional valgrindSupport valgrind
-    ;
-
-    CXXFLAGS = lib.optionalString stdenv.cc.isClang "-std=c++11";
-
-    configureFlags =
-      # Disable all extensions
-      [ "--disable-all" ]
-
-      # PCRE
-      ++ lib.optionals (lib.versionAtLeast version "7.4") [ "--with-external-pcre=${pcre'.dev}" ]
-      ++ lib.optionals (lib.versions.majorMinor version == "7.3") [ "--with-pcre-regex=${pcre'.dev}" ]
-      ++ lib.optionals (lib.versionOlder version "7.3") [ "--with-pcre-regex=${pcre'.dev}" ]
-      ++ [ "PCRE_LIBDIR=${pcre'}" ]
-
-
-      # Enable sapis
-      ++ lib.optional (!cgiSupport) "--disable-cgi"
-      ++ lib.optional (!cliSupport) "--disable-cli"
-      ++ lib.optional fpmSupport    "--enable-fpm"
-      ++ lib.optional pearSupport [ "--with-pear=$(out)/lib/php/pear" "--enable-xml" "--with-libxml" ]
-      ++ lib.optional (pearSupport && (lib.versionOlder version "7.4")) "--enable-libxml"
-      ++ lib.optional pharSupport   "--enable-phar"
-      ++ lib.optional phpdbgSupport "--enable-phpdbg"
-
-
-      # Misc flags
-      ++ lib.optional apxs2Support "--with-apxs2=${apacheHttpd.dev}/bin/apxs"
-      ++ lib.optional argon2Support "--with-password-argon2=${libargon2}"
-      ++ lib.optional cgotoSupport "--enable-re2c-cgoto"
-      ++ lib.optional embedSupport "--enable-embed"
-      ++ lib.optional (!ipv6Support) "--disable-ipv6"
-      ++ lib.optional systemdSupport "--with-fpm-systemd"
-      ++ lib.optional valgrindSupport "--with-valgrind=${valgrind.dev}"
-      ++ lib.optional ztsSupport "--enable-maintainer-zts"
-    ;
-
-    hardeningDisable = [ "bindnow" ];
-
-    preConfigure = ''
-      # Don't record the configure flags since this causes unnecessary
-      # runtime dependencies
-      for i in main/build-defs.h.in scripts/php-config.in; do
-        substituteInPlace $i \
-          --replace '@CONFIGURE_COMMAND@' '(omitted)' \
-          --replace '@CONFIGURE_OPTIONS@' "" \
-          --replace '@PHP_LDFLAGS@' ""
-      done
-
-      export EXTENSION_DIR=$out/lib/php/extensions
-
-      ./buildconf --copy --force
-
-      if test -f $src/genfiles; then
-        ./genfiles
-      fi
-    '' + lib.optionalString stdenv.isDarwin ''
-      substituteInPlace configure --replace "-lstdc++" "-lc++"
-    '';
-
-    postInstall = ''
-      test -d $out/etc || mkdir $out/etc
-      cp php.ini-production $out/etc/php.ini
-    '';
-
-    postFixup = ''
-      mkdir -p $dev/bin $dev/share/man/man1
-      mv $out/bin/phpize $out/bin/php-config $dev/bin/
-      mv $out/share/man/man1/phpize.1.gz \
-         $out/share/man/man1/php-config.1.gz \
-         $dev/share/man/man1/
-    '';
-
-    src = fetchurl {
-      url = "https://www.php.net/distributions/php-${version}.tar.bz2";
-      inherit sha256;
-    };
-
-    patches = [ ./fix-paths-php7.patch ] ++ extraPatches;
-
-    separateDebugInfo = true;
-
-    outputs = [ "out" "dev" ];
-
-    meta = with stdenv.lib; {
-      description = "An HTML-embedded scripting language";
-      homepage = "https://www.php.net/";
-      license = licenses.php301;
-      maintainers = with maintainers; [ globin etu ma27 ];
-      platforms = platforms.all;
-      outputsToInstall = [ "out" "dev" ];
-    };
-  };
-
-  generic' = { version, sha256, self, selfWithExtensions, ... }@args:
-    let
-      php = generic (builtins.removeAttrs args [ "self" "selfWithExtensions" ]);
-
-      php-packages = (callPackage ../../../top-level/php-packages.nix {
-        php = self;
-        phpWithExtensions = selfWithExtensions;
-      });
-
-      buildEnv = { extensions ? (_: []), extraConfig ? "" }:
-        let
-          getExtName = ext: lib.removePrefix "php-" (builtins.parseDrvName ext.name).name;
-          enabledExtensions = extensions php-packages.extensions;
-
-          # Generate extension load configuration snippets from the
-          # extension parameter. This is an attrset suitable for use
-          # with textClosureList, which is used to put the strings in
-          # the right order - if a plugin which is dependent on
-          # another plugin is placed before its dependency, it will
-          # fail to load.
-          extensionTexts =
-            lib.listToAttrs
-              (map (ext:
+    { callPackage, lib, stdenv, nixosTests, config, fetchurl, makeWrapper
+    , symlinkJoin, writeText, autoconf, automake, bison, flex, libtool
+    , pkgconfig, re2c, apacheHttpd, libargon2, libxml2, pcre, pcre2
+    , systemd, valgrind
+
+    , version
+    , sha256
+    , extraPatches ? []
+
+    # Sapi flags
+    , cgiSupport ? true
+    , cliSupport ? true
+    , fpmSupport ? true
+    , pearSupport ? true
+    , pharSupport ? true
+    , phpdbgSupport ? true
+
+    # Misc flags
+    , apxs2Support ? !stdenv.isDarwin
+    , argon2Support ? true
+    , cgotoSupport ? false
+    , embedSupport ? false
+    , ipv6Support ? true
+    , systemdSupport ? stdenv.isLinux
+    , valgrindSupport ? true
+    , ztsSupport ? apxs2Support
+    }@args:
+      let
+        # buildEnv wraps php to provide additional extensions and
+        # configuration. Its usage is documented in
+        # doc/languages-frameworks/php.section.md.
+        #
+        # Create a buildEnv with earlier overridden values and
+        # extensions functions in its closure. This is necessary for
+        # consecutive calls to buildEnv and overrides to work as
+        # expected.
+        mkBuildEnv = prevArgs: prevExtensionFunctions: lib.makeOverridable (
+          { extensions ? ({...}: []), extraConfig ? "", ... }@innerArgs:
+            let
+              allArgs = args // prevArgs // innerArgs;
+              filteredArgs = builtins.removeAttrs allArgs [ "extensions" "extraConfig" ];
+              php = generic filteredArgs;
+
+              php-packages = (callPackage ../../../top-level/php-packages.nix {
+                php = phpWithExtensions;
+              });
+
+              allExtensionFunctions = prevExtensionFunctions ++ [ extensions ];
+              enabledExtensions =
+                builtins.foldl'
+                  (state: f:
+                    f { enabled = state; all = php-packages.extensions; })
+                  []
+                  allExtensionFunctions;
+
+              getExtName = ext: lib.removePrefix "php-" (builtins.parseDrvName ext.name).name;
+
+              # Recursively get a list of all internal dependencies
+              # for a list of extensions.
+              getDepsRecursively = extensions:
                 let
-                  extName = getExtName ext;
-                  type = "${lib.optionalString (ext.zendExtension or false) "zend_"}extension";
+                  deps = lib.concatMap
+                           (ext: ext.internalDeps or [])
+                           extensions;
                 in
-                  lib.nameValuePair extName {
-                    text = "${type}=${ext}/lib/php/extensions/${extName}.so";
-                    deps = lib.optionals (ext ? internalDeps)
-                      (map getExtName ext.internalDeps);
-                  })
-                enabledExtensions);
-
-          extNames = map getExtName enabledExtensions;
-          extraInit = writeText "custom-php.ini" ''
-            ${lib.concatStringsSep "\n"
-              (lib.textClosureList extensionTexts extNames)}
-            ${extraConfig}
+                  if ! (deps == []) then
+                    deps ++ (getDepsRecursively deps)
+                  else
+                    deps;
+
+              # Generate extension load configuration snippets from the
+              # extension parameter. This is an attrset suitable for use
+              # with textClosureList, which is used to put the strings in
+              # the right order - if a plugin which is dependent on
+              # another plugin is placed before its dependency, it will
+              # fail to load.
+              extensionTexts =
+                lib.listToAttrs
+                  (map (ext:
+                    let
+                      extName = getExtName ext;
+                      type = "${lib.optionalString (ext.zendExtension or false) "zend_"}extension";
+                    in
+                      lib.nameValuePair extName {
+                        text = "${type}=${ext}/lib/php/extensions/${extName}.so";
+                        deps = lib.optionals (ext ? internalDeps)
+                          (map getExtName ext.internalDeps);
+                      })
+                    (enabledExtensions ++ (getDepsRecursively enabledExtensions)));
+
+              extNames = map getExtName enabledExtensions;
+              extraInit = writeText "php.ini" ''
+                ${lib.concatStringsSep "\n"
+                  (lib.textClosureList extensionTexts extNames)}
+                ${extraConfig}
+              '';
+
+              phpWithExtensions = symlinkJoin rec {
+                name = "php-with-extensions-${version}";
+                inherit (php) version;
+                nativeBuildInputs = [ makeWrapper ];
+                passthru = {
+                  buildEnv = mkBuildEnv allArgs allExtensionFunctions;
+                  withExtensions = mkWithExtensions allArgs allExtensionFunctions;
+                  phpIni = "${phpWithExtensions}/lib/php.ini";
+                  unwrapped = php;
+                  tests = nixosTests.php;
+                  inherit (php-packages) packages extensions;
+                };
+                paths = [ php ];
+                postBuild = ''
+                  cp ${extraInit} $out/lib/php.ini
+
+                  wrapProgram $out/bin/php --set PHP_INI_SCAN_DIR $out/lib
+
+                  if test -e $out/bin/php-fpm; then
+                    wrapProgram $out/bin/php-fpm --set PHP_INI_SCAN_DIR $out/lib
+                  fi
+                '';
+              };
+            in
+              phpWithExtensions);
+
+        mkWithExtensions = prevArgs: prevExtensionFunctions: extensions:
+          mkBuildEnv prevArgs prevExtensionFunctions { inherit extensions; };
+
+        pcre' = if (lib.versionAtLeast version "7.3") then pcre2 else pcre;
+      in
+        stdenv.mkDerivation {
+          pname = "php";
+
+          inherit version;
+
+          enableParallelBuilding = true;
+
+          nativeBuildInputs = [ autoconf automake bison flex libtool pkgconfig re2c ];
+
+          buildInputs =
+            # PCRE extension
+            [ pcre' ]
+
+            # Enable sapis
+            ++ lib.optional pearSupport [ libxml2.dev ]
+
+            # Misc deps
+            ++ lib.optional apxs2Support apacheHttpd
+            ++ lib.optional argon2Support libargon2
+            ++ lib.optional systemdSupport systemd
+            ++ lib.optional valgrindSupport valgrind
+          ;
+
+          CXXFLAGS = lib.optionalString stdenv.cc.isClang "-std=c++11";
+
+          configureFlags =
+            # Disable all extensions
+            [ "--disable-all" ]
+
+            # PCRE
+            ++ lib.optionals (lib.versionAtLeast version "7.4") [ "--with-external-pcre=${pcre'.dev}" ]
+            ++ lib.optionals (lib.versions.majorMinor version == "7.3") [ "--with-pcre-regex=${pcre'.dev}" ]
+            ++ lib.optionals (lib.versionOlder version "7.3") [ "--with-pcre-regex=${pcre'.dev}" ]
+            ++ [ "PCRE_LIBDIR=${pcre'}" ]
+
+
+            # Enable sapis
+            ++ lib.optional (!cgiSupport) "--disable-cgi"
+            ++ lib.optional (!cliSupport) "--disable-cli"
+            ++ lib.optional fpmSupport    "--enable-fpm"
+            ++ lib.optional pearSupport [ "--with-pear=$(out)/lib/php/pear" "--enable-xml" "--with-libxml" ]
+            ++ lib.optional (pearSupport && (lib.versionOlder version "7.4")) "--enable-libxml"
+            ++ lib.optional pharSupport   "--enable-phar"
+            ++ lib.optional phpdbgSupport "--enable-phpdbg"
+
+
+            # Misc flags
+            ++ lib.optional apxs2Support "--with-apxs2=${apacheHttpd.dev}/bin/apxs"
+            ++ lib.optional argon2Support "--with-password-argon2=${libargon2}"
+            ++ lib.optional cgotoSupport "--enable-re2c-cgoto"
+            ++ lib.optional embedSupport "--enable-embed"
+            ++ lib.optional (!ipv6Support) "--disable-ipv6"
+            ++ lib.optional systemdSupport "--with-fpm-systemd"
+            ++ lib.optional valgrindSupport "--with-valgrind=${valgrind.dev}"
+            ++ lib.optional ztsSupport "--enable-maintainer-zts"
+          ;
+
+          hardeningDisable = [ "bindnow" ];
+
+          preConfigure = ''
+            # Don't record the configure flags since this causes unnecessary
+            # runtime dependencies
+            for i in main/build-defs.h.in scripts/php-config.in; do
+              substituteInPlace $i \
+                --replace '@CONFIGURE_COMMAND@' '(omitted)' \
+                --replace '@CONFIGURE_OPTIONS@' "" \
+                --replace '@PHP_LDFLAGS@' ""
+            done
+
+            export EXTENSION_DIR=$out/lib/php/extensions
+
+            ./buildconf --copy --force
+
+            if test -f $src/genfiles; then
+              ./genfiles
+            fi
+          '' + lib.optionalString stdenv.isDarwin ''
+            substituteInPlace configure --replace "-lstdc++" "-lc++"
           '';
-        in
-          symlinkJoin {
-            name = "php-with-extensions-${version}";
-            inherit (php) version;
-            nativeBuildInputs = [ makeWrapper ];
-            passthru = {
-              inherit buildEnv withExtensions enabledExtensions;
-              inherit (php-packages) packages extensions;
-            };
-            paths = [ php ];
-            postBuild = ''
-              cp ${extraInit} $out/lib/custom-php.ini
-
-              wrapProgram $out/bin/php --set PHP_INI_SCAN_DIR $out/lib
-
-              if test -e $out/bin/php-fpm; then
-                 wrapProgram $out/bin/php-fpm --set PHP_INI_SCAN_DIR $out/lib
-              fi
-            '';
+
+          postInstall = ''
+            test -d $out/etc || mkdir $out/etc
+            cp php.ini-production $out/etc/php.ini
+          '';
+
+          postFixup = ''
+            mkdir -p $dev/bin $dev/share/man/man1
+            mv $out/bin/phpize $out/bin/php-config $dev/bin/
+            mv $out/share/man/man1/phpize.1.gz \
+               $out/share/man/man1/php-config.1.gz \
+               $dev/share/man/man1/
+          '';
+
+          src = fetchurl {
+            url = "https://www.php.net/distributions/php-${version}.tar.bz2";
+            inherit sha256;
           };
 
-      withExtensions = extensions: buildEnv { inherit extensions; };
-    in
-      php.overrideAttrs (_: {
-        passthru = {
-          enabledExtensions = [];
-          inherit buildEnv withExtensions;
-          inherit (php-packages) packages extensions;
+          patches = [ ./fix-paths-php7.patch ] ++ extraPatches;
+
+          separateDebugInfo = true;
+
+          outputs = [ "out" "dev" ];
+
+          passthru = {
+            buildEnv = mkBuildEnv {} [];
+            withExtensions = mkWithExtensions {} [];
+          };
+
+          meta = with stdenv.lib; {
+            description = "An HTML-embedded scripting language";
+            homepage = "https://www.php.net/";
+            license = licenses.php301;
+            maintainers = with maintainers; [ globin etu ma27 ];
+            platforms = platforms.all;
+            outputsToInstall = [ "out" "dev" ];
+          };
         };
-      });
 
-  php72base = generic' {
+  php72base = callPackage generic (_args // {
     version = "7.2.29";
     sha256 = "08xry2fgqgg8s0ym1hh11wkbr36av3zq1bn4krbciw1b7x8gb8ga";
-    self = php72base;
-    selfWithExtensions = php72;
 
     # https://bugs.php.net/bug.php?id=76826
     extraPatches = lib.optional stdenv.isDarwin ./php72-darwin-isfinite.patch;
-  };
+  });
 
-  php73base = generic' {
+  php73base = callPackage generic (_args // {
     version = "7.3.16";
     sha256 = "0bh499v9dfgh9k51w4rird1slb9rh9whp5h37fb84c98d992s1xq";
-    self = php73base;
-    selfWithExtensions = php73;
 
     # https://bugs.php.net/bug.php?id=76826
     extraPatches = lib.optional stdenv.isDarwin ./php73-darwin-isfinite.patch;
-  };
+  });
 
-  php74base = generic' {
+  php74base = callPackage generic (_args // {
     version = "7.4.4";
     sha256 = "17w2m4phhpj76x5fx67vgjrlkcczqvky3f5in1kjg2pch90qz3ih";
-    self = php74base;
-    selfWithExtensions = php74;
-  };
+  });
 
-  defaultPhpExtensions = extensions: with extensions; ([
+  defaultPhpExtensions = { all, ... }: with all; ([
     bcmath calendar curl ctype dom exif fileinfo filter ftp gd
     gettext gmp iconv intl json ldap mbstring mysqli mysqlnd opcache
     openssl pcntl pdo pdo_mysql pdo_odbc pdo_pgsql pdo_sqlite pgsql
@@ -252,13 +281,13 @@ let
     tokenizer xmlreader xmlwriter zip zlib
   ] ++ lib.optionals (!stdenv.isDarwin) [ imap ]);
 
-  defaultPhpExtensionsWithHash = extensions:
-    (defaultPhpExtensions extensions) ++ [ extensions.hash ];
+  defaultPhpExtensionsWithHash = { all, ... }:
+    (defaultPhpExtensions { inherit all; }) ++ [ all.hash ];
 
   php74 = php74base.withExtensions defaultPhpExtensions;
   php73 = php73base.withExtensions defaultPhpExtensionsWithHash;
   php72 = php72base.withExtensions defaultPhpExtensionsWithHash;
 
 in {
-  inherit php72base php73base php74base php72 php73 php74;
+  inherit php72 php73 php74;
 }
diff --git a/pkgs/servers/http/unit/default.nix b/pkgs/servers/http/unit/default.nix
index 1e3ddb4ad8f1..0779a31f1064 100644
--- a/pkgs/servers/http/unit/default.nix
+++ b/pkgs/servers/http/unit/default.nix
@@ -1,8 +1,8 @@
 { stdenv, fetchFromGitHub, which
 , withPython2 ? false, python2
 , withPython3 ? true, python3, ncurses
-, withPHP72 ? false, php72base
-, withPHP73 ? true, php73base
+, withPHP72 ? false, php72
+, withPHP73 ? true, php73
 , withPerl528 ? false, perl528
 , withPerl530 ? true, perl530
 , withPerldevel ? false, perldevel
@@ -18,16 +18,16 @@ with stdenv.lib;
 
 let
   phpConfig = {
-    config.php.embed = true;
-    config.php.apxs2 = false;
-    config.php.systemd = false;
-    config.php.phpdbg = false;
-    config.php.cgi = false;
-    config.php.fpm = false;
+    embedSupport = true;
+    apxs2Support = false;
+    systemdSupport = false;
+    phpdbgSupport = false;
+    cgiSupport = false;
+    fpmSupport = false;
   };
 
-  php72-unit = php72base.override phpConfig;
-  php73-unit = php73base.override phpConfig;
+  php72-unit = php72.override phpConfig;
+  php73-unit = php73.override phpConfig;
 in stdenv.mkDerivation rec {
   version = "1.16.0";
   pname = "unit";
@@ -71,8 +71,8 @@ in stdenv.mkDerivation rec {
   postConfigure = ''
     ${optionalString withPython2    "./configure python --module=python2  --config=${python2}/bin/python2-config  --lib-path=${python2}/lib"}
     ${optionalString withPython3    "./configure python --module=python3  --config=${python3}/bin/python3-config  --lib-path=${python3}/lib"}
-    ${optionalString withPHP72      "./configure php    --module=php72    --config=${php72-unit.dev}/bin/php-config    --lib-path=${php72-unit}/lib"}
-    ${optionalString withPHP73      "./configure php    --module=php73    --config=${php73-unit.dev}/bin/php-config    --lib-path=${php73-unit}/lib"}
+    ${optionalString withPHP72      "./configure php    --module=php72    --config=${php72-unit.unwrapped.dev}/bin/php-config --lib-path=${php72-unit}/lib"}
+    ${optionalString withPHP73      "./configure php    --module=php73    --config=${php73-unit.unwrapped.dev}/bin/php-config --lib-path=${php73-unit}/lib"}
     ${optionalString withPerl528    "./configure perl   --module=perl528  --perl=${perl528}/bin/perl"}
     ${optionalString withPerl530    "./configure perl   --module=perl530  --perl=${perl530}/bin/perl"}
     ${optionalString withPerldevel  "./configure perl   --module=perldev  --perl=${perldevel}/bin/perl"}
diff --git a/pkgs/servers/uwsgi/default.nix b/pkgs/servers/uwsgi/default.nix
index 29b807f17920..0f0d2c23e4c4 100644
--- a/pkgs/servers/uwsgi/default.nix
+++ b/pkgs/servers/uwsgi/default.nix
@@ -8,8 +8,8 @@
 }:
 
 let php-embed = php.override {
-      config.php.embed = true;
-      config.php.apxs2 = false;
+      embedSupport = true;
+      apxs2Support = false;
     };
 
     pythonPlugin = pkg : lib.nameValuePair "python${if pkg.isPy2 then "2" else "3"}" {
diff --git a/pkgs/top-level/aliases.nix b/pkgs/top-level/aliases.nix
index df8c42cc594e..4837995d11a7 100644
--- a/pkgs/top-level/aliases.nix
+++ b/pkgs/top-level/aliases.nix
@@ -339,48 +339,50 @@ mapAliases ({
   pg_tmp = ephemeralpg; # added 2018-01-16
 
   php-embed = throw ''
-    php*-embed has been dropped, you can build the same package by using
-     something similar with this following snippet:
-    (php74.override { config.php.embed = true; config.php.apxs2 = false; })
+    php*-embed has been dropped, you can build something similar
+    with the following snippet:
+    php74.override { embedSupport = true; apxs2Support = false; }
   ''; # added 2020-04-01
   php72-embed = php-embed; # added 2020-04-01
   php73-embed = php-embed; # added 2020-04-01
   php74-embed = php-embed; # added 2020-04-01
 
   phpPackages-embed = throw ''
-    php*Packages-embed has been dropped, you can build the same package by using
-     something similar with this following snippet:
-    (php74.override { config.php.embed = true; config.php.apxs2 = false; }).packages
+    php*Packages-embed has been dropped, you can build something
+    similar with the following snippet:
+    (php74.override { embedSupport = true; apxs2Support = false; }).packages
   ''; # added 2020-04-01
   php74Packages-embed = phpPackages-embed;
   php73Packages-embed = phpPackages-embed;
   php72Packages-embed = phpPackages-embed;
 
   php-unit = throw ''
-    php*-unit has been dropped, you can build the same package by using
-     something similar with this following snippet:
-    (php74.override {
-      config.php.embed = true;
-      config.php.apxs2 = false;
-      config.php.systemd = false;
-      config.php.phpdbg = false;
-      config.php.cgi = false;
-      config.php.fpm = false; })
+    php*-unit has been dropped, you can build something similar with
+    the following snippet:
+    php74.override {
+      embedSupport = true;
+      apxs2Support = false;
+      systemdSupport = false;
+      phpdbgSupport = false;
+      cgiSupport = false;
+      fpmSupport = false;
+    }
   ''; # added 2020-04-01
   php72-unit = php-unit; # added 2020-04-01
   php73-unit = php-unit; # added 2020-04-01
   php74-unit = php-unit; # added 2020-04-01
 
   phpPackages-unit = throw ''
-    php*Packages-unit has been dropped, you can build the same package by using
-     something similar with this following snippet:
+    php*Packages-unit has been dropped, you can build something
+     similar with this following snippet:
     (php74.override {
-      config.php.embed = true;
-      config.php.apxs2 = false;
-      config.php.systemd = false;
-      config.php.phpdbg = false;
-      config.php.cgi = false;
-      config.php.fpm = false; }).packages
+      embedSupport = true;
+      apxs2Support = false;
+      systemdSupport = false;
+      phpdbgSupport = false;
+      cgiSupport = false;
+      fpmSupport = false;
+    }).packages
   ''; # added 2020-04-01
   php74Packages-unit = phpPackages-unit;
   php73Packages-unit = phpPackages-unit;
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index 49a0aa35c7c3..11c9ad361fd3 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -9457,9 +9457,9 @@ in
   php73Extensions = recurseIntoAttrs php73.extensions;
   php74Extensions = recurseIntoAttrs php74.extensions;
 
-  inherit (callPackages ../development/interpreters/php {
+  inherit (callPackage ../development/interpreters/php {
     stdenv = if stdenv.cc.isClang then llvmPackages_6.stdenv else stdenv;
-  }) php74 php73 php72 php74base php73base php72base;
+  }) php74 php73 php72;
 
   picoc = callPackage ../development/interpreters/picoc {};
 
diff --git a/pkgs/top-level/php-packages.nix b/pkgs/top-level/php-packages.nix
index 0cda058459df..b9247cf0a177 100644
--- a/pkgs/top-level/php-packages.nix
+++ b/pkgs/top-level/php-packages.nix
@@ -1,4 +1,4 @@
-{ stdenv, lib, pkgs, fetchgit, php, phpWithExtensions, autoconf, pkgconfig, re2c
+{ stdenv, lib, pkgs, fetchgit, php, autoconf, pkgconfig, re2c
 , gettext, bzip2, curl, libxml2, openssl, gmp, icu, oniguruma, libsodium
 , html-tidy, libzip, zlib, pcre, pcre2, libxslt, aspell, openldap, cyrus_sasl
 , uwimap, pam, libiconv, enchant1, libXpm, gd, libwebp, libjpeg, libpng
@@ -8,7 +8,8 @@
 
 let
   buildPecl = import ../build-support/build-pecl.nix {
-    inherit php lib;
+    php = php.unwrapped;
+    inherit lib;
     inherit (pkgs) stdenv autoreconfHook fetchurl re2c;
   };
 
@@ -43,7 +44,7 @@ in
       installPhase = ''
         mkdir -p $out/bin
         install -D $src $out/libexec/box/box.phar
-        makeWrapper ${phpWithExtensions}/bin/php $out/bin/box \
+        makeWrapper ${php}/bin/php $out/bin/box \
           --add-flags "-d phar.readonly=0 $out/libexec/box/box.phar"
       '';
 
@@ -71,7 +72,7 @@ in
       installPhase = ''
         mkdir -p $out/bin
         install -D $src $out/libexec/composer/composer.phar
-        makeWrapper ${phpWithExtensions}/bin/php $out/bin/composer \
+        makeWrapper ${php}/bin/php $out/bin/composer \
           --add-flags "$out/libexec/composer/composer.phar" \
           --prefix PATH : ${pkgs.lib.makeBinPath [ pkgs.unzip ]}
       '';
@@ -163,7 +164,7 @@ in
       installPhase = ''
         mkdir -p $out/bin
         install -D $src $out/libexec/phpcbf/phpcbf.phar
-        makeWrapper ${phpWithExtensions}/bin/php $out/bin/phpcbf \
+        makeWrapper ${php}/bin/php $out/bin/phpcbf \
           --add-flags "$out/libexec/phpcbf/phpcbf.phar"
       '';
 
@@ -190,7 +191,7 @@ in
       installPhase = ''
         mkdir -p $out/bin
         install -D $src $out/libexec/phpcs/phpcs.phar
-        makeWrapper ${phpWithExtensions}/bin/php $out/bin/phpcs \
+        makeWrapper ${php}/bin/php $out/bin/phpcs \
           --add-flags "$out/libexec/phpcs/phpcs.phar"
       '';
 
@@ -217,7 +218,7 @@ in
       installPhase = ''
         mkdir -p $out/bin
         install -D $src $out/libexec/phpstan/phpstan.phar
-        makeWrapper ${phpWithExtensions}/bin/php $out/bin/phpstan \
+        makeWrapper ${php}/bin/php $out/bin/phpstan \
           --add-flags "$out/libexec/phpstan/phpstan.phar"
       '';
 
@@ -537,7 +538,7 @@ in
     };
 
     pdo_oci = buildPecl rec {
-      inherit (php) src version;
+      inherit (php.unwrapped) src version;
 
       pname = "pdo_oci";
       sourceRoot = "php-${version}/ext/pdo_oci";
@@ -548,8 +549,8 @@ in
       internalDeps = [ php.extensions.pdo ];
 
       postPatch = ''
-      sed -i -e 's|OCISDKMANINC=`.*$|OCISDKMANINC="${pkgs.oracle-instantclient.dev}/include"|' config.m4
-    '';
+        sed -i -e 's|OCISDKMANINC=`.*$|OCISDKMANINC="${pkgs.oracle-instantclient.dev}/include"|' config.m4
+      '';
     };
 
     pdo_sqlsrv = buildPecl {
@@ -746,11 +747,11 @@ in
       pname = "php-${name}";
       extensionName = name;
 
-      inherit (php) version src;
+      inherit (php.unwrapped) version src;
       sourceRoot = "php-${php.version}/ext/${name}";
 
       enableParallelBuilding = true;
-      nativeBuildInputs = [ php autoconf pkgconfig re2c ];
+      nativeBuildInputs = [ php.unwrapped autoconf pkgconfig re2c ];
       inherit configureFlags internalDeps buildInputs
         zendExtension doCheck;