# PHP Interpreter (php-src) — User Guide

PHP is a popular general-purpose scripting language that is especially suited to web development. This guide covers the **`php-src` repository** — the official C source code of the PHP interpreter itself. It is written for people who build PHP from source, run the bundled command-line tools (`php`, `php-cgi`, `php-fpm`, `phpdbg`), and configure a PHP runtime via `php.ini`.

> [!NOTE]
> This guide documents the **interpreter source tree**, not the PHP language. For the PHP *language* manual (functions, syntax, classes), see [php.net/docs](https://www.php.net/docs). Here you will learn how to compile PHP, what the binaries do, and how to configure the runtime they produce.

This source tree builds **PHP 8.6** (the `master` development branch). Everything below is derived directly from the source at commit `95b5b487`.

---

## Table of Contents

1. [Quick Start](#1-quick-start)
2. [What You Are Building](#2-what-you-are-building)
3. [Requirements](#3-requirements)
4. [Building PHP From Source](#4-building-php-from-source)
5. [Running the PHP CLI (`php`)](#5-running-the-php-cli-php)
6. [The Built-in Web Server](#6-the-built-in-web-server)
7. [The Other SAPIs (`php-cgi`, `php-fpm`, `phpdbg`)](#7-the-other-sapis-php-cgi-php-fpm-phpdbg)
8. [Configuring PHP with `php.ini`](#8-configuring-php-with-phpini)
9. [Extensions](#9-extensions)
10. [Common Tasks](#10-common-tasks)
11. [Running the Test Suite](#11-running-the-test-suite)
12. [Troubleshooting](#12-troubleshooting)
13. [FAQ](#13-faq)
14. [Reference](#14-reference)

---

## 1. Quick Start

The fastest path from a fresh Git clone to a working `php` binary on a Debian/Ubuntu machine:

```bash
# 1. Install build prerequisites
sudo apt install -y pkg-config build-essential autoconf bison re2c \
    libxml2-dev libsqlite3-dev

# 2. Clone the source
git clone https://github.com/php/php-src.git
cd php-src

# 3. Generate the configure script
./buildconf

# 4. Configure the build (production defaults)
./configure

# 5. Compile (use all CPU cores)
make -j"$(nproc)"

# 6. Run the freshly built interpreter
sapi/cli/php -v
```

Expected output from the final command:

```text
PHP 8.6.0-dev (cli) (built: ... ) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.6.0-dev, Copyright (c) Zend Technologies
```

> [!TIP]
> You do not need to `make install` to use the binary. After a build, the CLI lives at `sapi/cli/php` inside the source tree and runs in place — ideal for testing changes.

> [!NOTE]
> On a minimal Git build you need `autoconf`, `bison`, and `re2c`. A default build additionally needs `libxml2` and `libsqlite3`. See [Requirements](#3-requirements) for other platforms.

---

## 2. What You Are Building

The `php-src` tree compiles into several executables, each called a **SAPI** (Server Application Programming Interface — the layer that connects the PHP engine to a host environment). When you run `./configure && make`, you get a different set of binaries depending on which SAPIs you enabled.

| Binary | SAPI | What it is for | Built by default |
|--------|------|----------------|------------------|
| `php` | `cli` | Command-line interpreter, scripts, REPL, built-in web server | Yes |
| `php-cgi` | `cgi` | CGI/FastCGI executable for traditional web servers | Yes |
| `php-fpm` | `fpm` | FastCGI Process Manager — the production web runtime | Opt-in (`--enable-fpm`) |
| `phpdbg` | `phpdbg` | Interactive step debugger for PHP scripts | Opt-in (`--enable-phpdbg`) |
| `libphp.so` | `apache2handler` | Apache module (`mod_php`) | Opt-in (`--with-apxs2`) |
| `libphp.so`/`.a` | `embed` | Embed PHP into a C/C++ application | Opt-in (`--enable-embed`) |
| — | `litespeed` | LiteSpeed web server LSAPI binary | Opt-in (`--enable-litespeed`) |

Internally, every SAPI sits on top of two shared layers:

```text
┌───────────────────────────────────────────────────────────┐
│  SAPI binaries:  php   php-cgi   php-fpm   phpdbg   mod_php │
├───────────────────────────────────────────────────────────┤
│  Bundled extensions (ext/):  standard, pdo, mbstring, ...  │
├───────────────────────────────────────────────────────────┤
│  PHP core (main/):  startup, php.ini, streams, SAPI glue   │
├───────────────────────────────────────────────────────────┤
│  Zend Engine (Zend/):  lexer → compiler → opcodes → VM     │
└───────────────────────────────────────────────────────────┘
```

> [!NOTE]
> The deep architecture (how the Zend Engine compiles and executes code, the memory manager, OPcache, the JIT) is covered in the **Admin Guide**. This User Guide focuses on building and using the binaries.

---

## 3. Requirements

### Build toolchain

| Tool | Why it is needed | Minimal build | Default build |
|------|------------------|---------------|---------------|
| C compiler (`gcc`/`clang`) | Compiles the C sources | Required | Required |
| `make` | Drives the build | Required | Required |
| `autoconf` | Generates `configure` via `./buildconf` | Required | Required |
| `bison` | Generates the PHP language parser | Required | Required |
| `re2c` | Generates the lexer/scanner | Required | Required |
| `pkg-config` | Locates system libraries | Recommended | Recommended |
| `libxml2` | Required by several core extensions | — | Required |
| `libsqlite3` | Default SQLite/PDO support | — | Required |

### Install prerequisites by platform

=== "Ubuntu / Debian"

    ```bash
    sudo apt install -y pkg-config build-essential autoconf bison re2c \
        libxml2-dev libsqlite3-dev
    ```

=== "Fedora"

    ```bash
    sudo dnf install re2c bison autoconf make ccache libxml2-devel sqlite-devel
    ```

=== "macOS (Homebrew)"

    ```bash
    brew install autoconf bison re2c libiconv libxml2 sqlite
    ```

=== "macOS (MacPorts)"

    ```bash
    sudo port install autoconf bison re2c libiconv libxml2 sqlite3
    ```

> [!IMPORTANT]
> On macOS, the system `bison` is usually too old. Homebrew/MacPorts install a newer `bison` that is **not** on the default `PATH`. Add it before running `./buildconf` (Homebrew prints the exact `export PATH=...` line after install).

### Prebuilt binaries (skip building entirely)

If you only want to *run* PHP, you do not need this repository:

- **Windows:** download `*.exe` builds from [windows.php.net](https://windows.php.net) and run them directly after extracting.
- **Linux/macOS:** use your distribution's package manager or see the [installation chapter](https://www.php.net/install) at php.net.

> [!TIP]
> Build from source when you are developing PHP itself, need a custom extension set, want the JIT/debug build, or are running an architecture without prebuilt binaries.

---

## 4. Building PHP From Source

The build is a standard Autotools flow: `buildconf` → `configure` → `make` → (optionally) `make install`.

### Step 1 — Generate `configure`

```bash
./buildconf
```

This runs `autoconf` to produce the `configure` script from `configure.ac` and the per-extension `config.m4` files.

> [!NOTE]
> On a **release tarball** from php.net, `configure` already exists and you can skip `./buildconf`. On a Git checkout you must run it. Use `./buildconf --force` if `configure` is stale after pulling changes.

### Step 2 — Configure the build

```bash
# For development (assertions, debug symbols, no optimization surprises)
./configure --enable-debug

# For production
./configure
```

See every available switch with:

```bash
./configure --help
```

The configure step decides **which SAPIs and extensions** are compiled in. A few of the most common switches:

| Switch | Effect |
|--------|--------|
| `--enable-debug` | Debug build: assertions on, symbols, leak checks. Recommended for development. |
| `--enable-fpm` | Build the `php-fpm` FastCGI process manager. |
| `--enable-phpdbg` | Build the `phpdbg` interactive debugger. |
| `--enable-embed` | Build the embed SAPI (`libphp`) to embed PHP in C/C++. |
| `--with-apxs2[=FILE]` | Build the Apache 2 module (`mod_php`). |
| `--enable-opcache-jit` | Enable JIT support in OPcache (on by default when OPcache builds). |
| `--disable-all` | Start from a minimal build and add only what you `--enable`/`--with`. |
| `--with-config-file-path=PATH` | Compile in the directory PHP searches for `php.ini`. |
| `--with-config-file-scan-dir=PATH` | Compile in an extra directory of `*.ini` fragments. |
| `--prefix=PATH` | Installation prefix (default `/usr/local`). |

> [!TIP]
> For a lean, fast build while hacking on the engine, use `./configure --disable-all --enable-debug`. It skips the dozens of optional extensions and compiles in a fraction of the time.

A fuller list of extension and feature switches is in the [Reference](#14-reference).

### Step 3 — Compile

```bash
make -j"$(nproc)"
```

The `-j` flag sets the number of parallel jobs; matching it to your core count (`nproc`) is the usual choice.

> [!WARNING]
> A full default build compiles thousands of C files and can take several minutes even on a fast machine. Install `ccache` (Fedora command above includes it) to make rebuilds dramatically faster.

### Step 4 — Install (optional)

```bash
make install
```

`make install` copies the binaries, headers, and the `php` man pages into your `--prefix`. Depending on the prefix and your permissions it may require `sudo`.

> [!NOTE]
> If you only want to run the interpreter in place for testing, skip `make install` and call `sapi/cli/php` directly from the build tree.

### Verifying the build

```bash
sapi/cli/php --version
sapi/cli/php -m          # list compiled-in modules/extensions
sapi/cli/php -i | head   # full configuration dump (phpinfo)
```

---

## 5. Running the PHP CLI (`php`)

The `cli` SAPI is the workhorse: it runs scripts, evaluates inline code, lints files, starts a development web server, and provides an interactive shell. All forms accept the options listed in the [CLI reference](#cli-option-reference).

### Usage forms

```text
php [options] [-f] <file> [--] [args...]
php [options] -r <code> [--] [args...]
php [options] [-B <begin_code>] -R <code> [-E <end_code>] [--] [args...]
php [options] [-B <begin_code>] -F <file> [-E <end_code>] [--] [args...]
php [options] -S <addr>:<port> [-t docroot] [router]
php [options] -- [args...]
php [options] -a
```

### Run a script file

```bash
php script.php
php -f script.php          # explicit form, identical effect
php script.php arg1 arg2   # pass arguments (available in $argv)
```

> [!TIP]
> Use `--` to separate PHP options from script arguments when an argument starts with `-`:
> ```bash
> php script.php -- --verbose --name=foo
> ```

### Run inline code with `-r`

```bash
php -r 'echo PHP_VERSION, PHP_EOL;'
```

```text
8.6.0-dev
```

> [!NOTE]
> With `-r` you write PHP **without** the `<?php ?>` tags.

### Lint (syntax-check) a file with `-l`

```bash
php -l script.php
```

```text
No syntax errors detected in script.php
```

This parses the file and reports syntax errors without executing it — handy in CI and pre-commit hooks.

### Process input line-by-line (`-R` / `-F`)

The `-B`/`-R`/`-E` trio runs code before, for each input line, and after STDIN — an `awk`-like mode. `$argn` holds the current line; `$argi` the line number.

```bash
# Count non-empty lines from stdin
cat file.txt | php -B '$c=0;' -R 'if(trim($argn)!=="") $c++;' -E 'echo "$c\n";'
```

Use `-F <file>` instead of `-R <code>` to run a whole script per input line.

### Interactive shell (`-a`)

```bash
php -a
```

```text
Interactive shell

php >
```

> [!IMPORTANT]
> The interactive shell (`-a`) requires PHP to be built with the **readline** extension (`--with-readline` or `--with-libedit`). Without it, `-a` falls back to a much more limited line-buffered mode.

### Inspect the runtime

```bash
php -i                 # full phpinfo() text dump
php -m                 # list loaded modules (extensions)
php --ini              # show which php.ini files are loaded
php --ini=diff         # show only INI values that differ from built-in defaults
```

### Reflection helpers

PHP can print structured information about functions, classes, and extensions straight from the CLI:

```bash
php --rf str_replace   # reflect a function's signature
php --rc DateTime      # reflect a class
php --re json          # reflect an extension (its functions/classes/ini)
php --ri opcache       # show an extension's runtime configuration
php --rz <name>        # reflect a Zend extension
```

> [!TIP]
> `php --ri opcache` is the quickest way to confirm whether OPcache (and the JIT) is active and how it is configured, without writing a script.

### Override configuration per invocation

```bash
php -d memory_limit=512M -d display_errors=1 script.php   # set INI entries inline
php -c /path/to/custom.ini script.php                     # use a specific php.ini
php -n script.php                                         # ignore all php.ini files
```

> [!NOTE]
> `-d key=value` can be repeated. These overrides apply only to that single invocation, layered on top of the loaded `php.ini`.

---

## 6. The Built-in Web Server

The CLI ships a small web server intended for **local development and testing** — never for production.

### Start the server

```bash
php -S localhost:8000
```

```text
[..] PHP 8.6.0-dev Development Server (http://localhost:8000) started
```

Serve files from a specific document root:

```bash
php -S localhost:8000 -t public/
```

### Use a router script

A router script lets a single front controller handle every request (the pattern most frameworks use):

```bash
php -S localhost:8000 router.php
```

Inside `router.php`, return `false` to let the server serve a real static file as-is:

```php
<?php
if (preg_match('#\.(?:png|jpg|css|js)$#', $_SERVER["REQUEST_URI"])) {
    return false; // serve the requested file directly
}
require __DIR__ . '/index.php'; // otherwise route through the app
```

> [!WARNING]
> The built-in server is single-threaded by default and has **no security hardening**. It is a development convenience only. For production, use `php-fpm` behind nginx/Apache, or `mod_php` — see the Admin Guide.

> [!TIP]
> Colorized CLI server output is controlled by the `cli_server.color` INI directive (`On` in the production template). Bind to `0.0.0.0:8000` to accept connections from other machines on your network — only do this on trusted networks.

---

## 7. The Other SAPIs (`php-cgi`, `php-fpm`, `phpdbg`)

### `php-cgi` — CGI / FastCGI executable

`php-cgi` is the CGI binary, used by web servers that speak CGI or FastCGI directly. It shares most options with the CLI plus a few CGI-specific ones:

```bash
php-cgi -b 127.0.0.1:9000    # run as a FastCGI server bound to host:port
php-cgi -T 10 script.php     # measure execution time, repeating 10 times
```

| Option | Meaning |
|--------|---------|
| `-b <address:port>\|<port>` | Bind path/address for an external FastCGI server. |
| `-T <count>` | Measure execution time, repeating the request `count` times. |
| `-q` | Quiet mode: do not generate HTTP headers. |

> [!NOTE]
> For new deployments prefer `php-fpm` over `php-cgi`. FPM is a purpose-built process manager with pooling, status reporting, and graceful reloads.

### `php-fpm` — FastCGI Process Manager

`php-fpm` is the production runtime that nginx and Apache talk to over FastCGI. It is configured through `php-fpm.conf` (global) and pool files in `php-fpm.d/`.

```bash
php-fpm -t                    # test (validate) the configuration and exit
php-fpm -F                    # run in the foreground (do not daemonize)
php-fpm -y /etc/php-fpm.conf  # use a specific config file
php-fpm -p /run/php           # set the prefix for relative paths
```

| Option | Meaning |
|--------|---------|
| `-t` / `--test` | Validate configuration; exit non-zero on error. Run this before every reload. |
| `-F` / `--nodaemonize` | Stay in the foreground (the right choice under systemd/Docker). |
| `-D` / `--daemonize` | Force daemonization. |
| `-y <file>` / `--fpm-config` | Path to the FPM config file. |
| `-p <prefix>` / `--prefix` | Prefix for relative paths in the config. |
| `-g <file>` / `--pid` | PID file path. |
| `-R` / `--allow-to-run-as-root` | Permit running the master as root (discouraged). |
| `-O` / `--force-stderr` | Force error output to stderr. |

> [!IMPORTANT]
> Always run `php-fpm -t` after editing a pool file. A syntax error caught at reload time can otherwise take your site down. Pool tuning (`pm`, `pm.max_children`, etc.) is covered in the Admin Guide.

### `phpdbg` — interactive debugger

`phpdbg` is a gdb-style interactive debugger for PHP scripts, built with `--enable-phpdbg`.

```bash
phpdbg script.php
```

```text
[Welcome to phpdbg, the interactive PHP debugger, v0.5.0]
To get help using phpdbg type "help" and press enter
[Please report bugs to <http://bugs.php.net/report.php>]
prompt>
```

Inside the prompt you can set breakpoints (`break`), step (`step`/`next`), continue (`run`/`continue`), and inspect state.

| Option | Meaning |
|--------|---------|
| `-r` | Run the script immediately on launch. |
| `-e` | Generate `ext_stmt` opcodes (finer-grained stepping). |
| `-E` | Step through `eval()`'d code. |
| `-i <file>` | Use a specific phpdbg init file. |
| `-I` | Ignore the init file. |
| `-p [<num>]` | Print/dump opcodes (disassemble). |
| `-S <name>` | Override the SAPI name. |
| `-z <ext>` | Load a Zend extension. |

> [!TIP]
> `phpdbg -p script.php` disassembles a script to its opcodes — a quick way to see what the compiler produced without running anything.

---

## 8. Configuring PHP with `php.ini`

PHP reads its runtime configuration from an INI file. The repository ships two starting points:

| File | Use for |
|------|---------|
| `php.ini-development` | Local development — verbose errors, more diagnostics. |
| `php.ini-production` | Servers — errors hidden from output, hardened defaults. |

Copy the one you want to PHP's config directory (revealed by `php --ini`):

```bash
cp php.ini-production /usr/local/lib/php.ini   # path depends on --with-config-file-path
php --ini                                      # confirm which file is now loaded
```

### How configuration is layered

1. Built-in defaults compiled into PHP.
2. The main `php.ini` (location set at build time, overridable with `-c`).
3. Extra `*.ini` files in the scan directory (`--with-config-file-scan-dir`).
4. Per-invocation `-d key=value` overrides (CLI) or `php_value`/`php_admin_value` (FPM pools).

```bash
php --ini=diff   # see exactly which entries differ from the built-in defaults
```

### Frequently changed directives

These values are taken verbatim from `php.ini-production`:

| Directive | Production default | Purpose |
|-----------|--------------------|---------|
| `memory_limit` | `128M` | Max memory a single script may allocate. |
| `max_execution_time` | `30` | Max seconds a script may run (CLI is exempt). |
| `max_input_time` | `60` | Max seconds spent parsing request input. |
| `post_max_size` | `8M` | Max size of a POST body. |
| `upload_max_filesize` | `2M` | Max size of a single uploaded file. |
| `max_file_uploads` | `20` | Max number of files per request. |
| `display_errors` | `Off` | Whether errors print to output (keep `Off` in production). |
| `display_startup_errors` | `Off` | Show errors during PHP startup. |
| `log_errors` | `On` | Write errors to the error log. |
| `error_reporting` | `E_ALL & ~E_DEPRECATED` | Which error levels are reported. |
| `expose_php` | `On` | Send the `X-Powered-By` header (set `Off` to hide PHP). |
| `default_charset` | `"UTF-8"` | Default charset for headers and output. |
| `allow_url_fopen` | `On` | Allow URL wrappers in file functions. |
| `allow_url_include` | `Off` | Allow `include`/`require` of URLs (keep `Off`). |
| `file_uploads` | `On` | Enable HTTP file uploads. |
| `variables_order` | `"GPCS"` | Which superglobals are populated and in what order. |
| `session.cookie_httponly` | `1` | Mark the session cookie `HttpOnly`. |
| `session.cookie_samesite` | `"Lax"` | `SameSite` attribute for the session cookie. |
| `session.use_strict_mode` | `1` | Reject uninitialized session IDs. |

> [!CAUTION]
> Keep `display_errors = Off` and `allow_url_include = Off` on any server reachable from the internet. The first leaks internal paths and data; the second is a classic remote-code-execution vector.

> [!TIP]
> Booleans accept `On`/`Off`, `1`/`0`, `true`/`false`, `yes`/`no`. Sizes accept `K`, `M`, `G` suffixes (e.g. `512M`).

A more complete directive table — including session, mail, and database-extension defaults — is in the [Reference](#14-reference).

---

## 9. Extensions

Extensions add functionality on top of the engine. PHP ships with **many bundled extensions** and supports loading additional ones.

### What ships in this tree

The `ext/` directory contains the bundled extensions, including (among ~70 total):

```text
bcmath  bz2  calendar  ctype  curl  date  dba  dom  exif  ffi  fileinfo
filter  ftp  gd  gettext  gmp  hash  iconv  intl  json  ldap  mbstring
mysqli  mysqlnd  odbc  opcache  openssl  pcntl  pcre  pdo  pdo_mysql
pdo_pgsql  pdo_sqlite  pgsql  phar  posix  random  readline  reflection
session  shmop  simplexml  snmp  soap  sockets  sodium  spl  sqlite3
standard  tidy  tokenizer  uri  xml  xmlreader  xmlwriter  xsl  zip  zlib
```

> [!NOTE]
> `ext/standard` and `ext/spl` are always present — they provide the core function library and standard data structures. `pcre`, `date`, `hash`, `json`, and `random` are likewise effectively always built in.

### Choosing extensions at build time

You select extensions when you run `./configure`:

```bash
./configure \
    --enable-mbstring \
    --with-curl \
    --with-openssl \
    --enable-sockets \
    --with-zip
```

- `--enable-NAME` is used for extensions with no external library dependency.
- `--with-NAME[=DIR]` is used for extensions that link a system library (point it at a non-standard install with `=DIR`).
- `--disable-all` plus explicit `--enable`/`--with` flags gives you a precisely minimal binary.

```bash
php -m   # confirm what actually got compiled in
```

### Loading shared extensions at runtime

Extensions built as shared objects (`.so`/`.dll`) are loaded via `php.ini`:

```ini
extension=curl
extension=/full/path/to/custom.so
zend_extension=opcache    ; Zend extensions (e.g. OPcache) use this directive
```

> [!IMPORTANT]
> OPcache is a **Zend extension** and must be loaded with `zend_extension=opcache`, not `extension=`. Loading it the wrong way silently fails.

### Adding a brand-new extension

The repository includes a skeleton generator for authoring a new extension:

```bash
php ext/ext_skel.php --ext my_extension
```

This scaffolds `ext/my_extension/` with the boilerplate (`config.m4`, a stub `.c`, tests) so you can start from a buildable shell. Additional community extensions are distributed via [PECL](https://pecl.php.net).

---

## 10. Common Tasks

### Check your PHP version and build flags

```bash
php -v          # version + Zend Engine version + thread-safety (NTS/ZTS)
php -i | grep -i 'Configure Command'   # the exact ./configure line used
```

### Find your loaded configuration files

```bash
php --ini
```

```text
Configuration File (php.ini) Path: /usr/local/lib
Loaded Configuration File:         /usr/local/lib/php.ini
Scan for additional .ini files in: /usr/local/lib/php.d
Additional .ini files parsed:      /usr/local/lib/php.d/10-opcache.ini
```

### Test a script's syntax across a project

```bash
find src -name '*.php' -print0 | xargs -0 -n1 php -l
```

### Serve a project locally

```bash
php -S 127.0.0.1:8080 -t public/ public/index.php
```

### Run a one-off snippet

```bash
php -r 'var_dump(json_decode(file_get_contents("php://stdin"), true));' < data.json
```

### Confirm an extension is available

```bash
php -m | grep -i curl        # is curl loaded?
php --ri curl                # detailed curl configuration
```

### Rebuild after pulling new source

```bash
git pull
./buildconf --force      # regenerate configure if build files changed
./configure --enable-debug   # re-run with your chosen flags
make -j"$(nproc)"
```

> [!TIP]
> If a rebuild behaves strangely after a big `git pull`, run `make clean` (or `git clean -xfd` to wipe all generated files) and rebuild from scratch.

---

## 11. Running the Test Suite

PHP ships an extensive `.phpt` test suite driven by `run-tests.php`. After a successful build:

```bash
make test
```

Run tests in parallel and target specific directories:

```bash
make TEST_PHP_ARGS=-j4 test          # 4 concurrent workers
make TESTS=tests/lang/ test          # only the language tests
make TESTS=ext/json test             # only the json extension's tests
```

> [!NOTE]
> Keep the number of jobs at or below your core count. Some extension test suites (mysqli, pgsql, ldap, snmp, …) need a running service and credentials supplied through environment variables — see each `ext/<name>/tests/README.md`.

### Testing with OPcache and the JIT

```bash
make test TESTS="-d opcache.jit_buffer_size=16M -d opcache.enable=1 \
    -d opcache.enable_cli=1 -d opcache.jit=tracing --repeat 2 \
    -j$(nproc) ext/opcache Zend"
```

- `opcache.jit_buffer_size=16M` allocates JIT memory (enabling the JIT in tests).
- `--repeat 2` re-runs each test — some JIT bugs only appear on the second request (first compiles the trace, second executes it).

> [!TIP]
> When chasing crashes, configure with `--enable-debug` and one of `--enable-address-sanitizer` (fast, needs rebuild) or run under valgrind via `-m --show-mem` in `TEST_PHP_ARGS` (no rebuild, slower).

---

## 12. Troubleshooting

### Error: `configure: error: bison is not found`

**Cause:** `bison` is missing or too old (common on macOS where the system version is ancient).
**Solution:** Install a recent `bison` (`brew install bison` / `apt install bison`) and put it on your `PATH` before `./buildconf`.
**Prevention:** Always install the full prerequisite list for your platform from [Requirements](#3-requirements).

### Error: `Cannot find autoconf. Please check your autoconf installation`

**Cause:** `./buildconf` cannot find `autoconf`.
**Solution:** Install `autoconf` (`apt install autoconf` / `brew install autoconf`), then re-run `./buildconf`.
**Prevention:** Install build prerequisites before cloning.

### Error: `configure: error: Package requirements (libxml-2.0) were not met`

**Cause:** The default build needs libxml2 development headers.
**Solution:** Install `libxml2-dev` (Debian) / `libxml2-devel` (Fedora) / `brew install libxml2`. If pkg-config still cannot find it, export `PKG_CONFIG_PATH` to its `.pc` directory.
**Prevention:** Install `libxml2` and `libsqlite3` dev packages, or use `--disable-libxml` plus `--without-sqlite3`/`--disable-dom` if you truly do not need them.

### Error: `No input file specified.` (under FPM/CGI)

**Cause:** The web server passed a `SCRIPT_FILENAME` that does not exist, or `security.limit_extensions` blocked it.
**Solution:** Verify the web server's `fastcgi_param SCRIPT_FILENAME` points to a real file; check the FPM pool's `security.limit_extensions`.
**Prevention:** Keep document-root and FastCGI parameters consistent between the web server and FPM.

### Warning: `opcache.memory_consumption cannot be changed when OPcache is already set up`

**Cause:** On ZTS builds, certain OPcache settings are locked once OPcache has initialized (observed in issue #22216 on 8.5 ZTS).
**Solution:** Set `opcache.memory_consumption` in the main `php.ini` so it is applied at startup, not via a per-request override.
**Prevention:** Configure OPcache sizing statically in `php.ini`; do not try to change it with `-d`/`ini_set()` after startup.

### `php -a` prints `Interactive mode enabled` but has no line editing

**Cause:** PHP was built without the readline extension.
**Solution:** Rebuild with `--with-readline` (GNU readline) or `--with-libedit` (BSD libedit).
**Prevention:** Include a readline library when you configure if you rely on the interactive shell.

### FPM: active processes exceed `pm.max_children`

**Cause:** Reported in issue #14212 — the status page can transiently show more active processes than the configured maximum during scaling.
**Solution:** Monitor over time rather than reacting to a single status snapshot; ensure `pm.max_children` is sized for your memory budget.
**Prevention:** Size `pm.max_children` from `available_RAM / avg_process_size` (see the Admin Guide).

### `make` fails after a `git pull`

**Cause:** Stale generated files (parser, lexer, or `configure`) no longer match the sources.
**Solution:** `./buildconf --force`, re-run `./configure`, then `make`. If it persists, `make clean` or `git clean -xfd` and rebuild.
**Prevention:** Re-run `./buildconf --force` whenever build-system files change upstream.

### Tests fail only with the JIT enabled

**Cause:** A JIT trace bug that surfaces on repeated execution.
**Solution:** Reproduce with `--repeat 2` and `opcache.protect_memory=1`; build with `--enable-debug` and AddressSanitizer to pinpoint it; report it upstream.
**Prevention:** Run the JIT test command from [Running the Test Suite](#11-running-the-test-suite) before relying on a JIT build.

---

## 13. FAQ

**Q: Is `php-src` the same as the PHP language documentation?**
No. `php-src` is the C source code of the interpreter. The language/function manual lives at [php.net/docs](https://www.php.net/docs). This repo's own `docs/` is internal documentation about the interpreter's implementation.

**Q: Which PHP version does this source build?**
This tree builds **PHP 8.6** (the development `master` branch — `8.6.0-dev`). The version constants live in `main/php_version.h`.

**Q: Do I have to run `make install`?**
No. The built binaries run in place (`sapi/cli/php`). Install only when you want them on your `PATH` and in system directories.

**Q: What is the difference between `php`, `php-cgi`, and `php-fpm`?**
`php` is the command-line interpreter (scripts, REPL, dev server). `php-cgi` is the CGI/FastCGI executable. `php-fpm` is the production FastCGI process manager that web servers connect to. See [Section 7](#7-the-other-sapis-php-cgi-php-fpm-phpdbg).

**Q: How do I know which extensions are compiled in?**
Run `php -m`. For details on one extension, `php --ri <name>`.

**Q: Why does `extension=opcache` not work?**
OPcache is a *Zend* extension. Load it with `zend_extension=opcache`.

**Q: How do I use a different `php.ini` for one command?**
`php -c /path/to/php.ini script.php`, or `php -n script.php` to ignore all INI files.

**Q: Can I set an INI value just for one run?**
Yes: `php -d memory_limit=512M script.php`. Repeat `-d` for multiple values.

**Q: Is the built-in web server safe for production?**
No. `php -S` is for development only. Use `php-fpm` behind nginx/Apache for production.

**Q: How do I build a minimal PHP for hacking on the engine?**
`./configure --disable-all --enable-debug && make -j$(nproc)`. This skips optional extensions and builds fast.

**Q: NTS vs ZTS — which do I have?**
`php -v` prints `(NTS)` for non-thread-safe or `(ZTS)` for thread-safe (Zend Thread Safety). NTS is the standard choice for CLI/FPM; ZTS is for threaded SAPIs.

**Q: How do I report a bug I found while building or testing?**
Open an issue at [github.com/php/php-src/issues](https://github.com/php/php-src/issues). Reference it in commits as `GH-NNNNNN`.

**Q: Where do additional (non-bundled) extensions come from?**
The [PECL](https://pecl.php.net) repository. Scaffold your own with `php ext/ext_skel.php --ext <name>`.

**Q: What does `php --ini=diff` show?**
Only the INI entries whose current value differs from PHP's built-in default — the fastest way to audit what your `php.ini` actually changes.

---

## 14. Reference

### CLI Option Reference

Complete option table for the `php` (cli) binary, from `sapi/cli/php_cli.c`:

| Short | Long | Arg | Description |
|-------|------|-----|-------------|
| `-a` | `--interactive` | — | Run as interactive shell (requires readline). |
| `-B` | `--process-begin` | code | Run PHP code before processing input lines. |
| `-C` | `--no-chdir` | — | Do not chdir to the script's directory (CGI compat). |
| `-c` | `--php-ini` | path | Look for `php.ini` in this directory/file. |
| `-d` | `--define` | foo[=bar] | Define an INI entry for this run. |
| `-E` | `--process-end` | code | Run PHP code after processing all input lines. |
| `-e` | `--profile-info` | — | Generate extended info for debugger/profiler. |
| `-F` | `--process-file` | file | Run a file for every input line. |
| `-f` | `--file` | file | Parse and execute a file. |
| `-h` | `--help` | — | Show help. |
| `-i` | `--info` | — | Print `phpinfo()`. |
| `-l` | `--syntax-check` | — | Syntax check only (lint). |
| `-m` | `--modules` | — | Show compiled-in modules. |
| `-n` | `--no-php-ini` | — | Do not load any `php.ini`. |
| `-q` | `--no-header` | — | Suppress HTTP headers (CGI compat). |
| `-R` | `--process-code` | code | Run code for every input line. |
| `-H` | `--hide-args` | — | Hide passed arguments from external tools. |
| `-r` | `--run` | code | Run code without `<?php ?>` tags. |
| `-s` | `--syntax-highlight` | — | Output HTML-highlighted source. |
| `-S` | `--server` | addr:port | Start the built-in web server. |
| `-t` | `--docroot` | dir | Document root for the built-in server. |
| `-w` | `--strip` | — | Output source with comments/whitespace stripped. |
| `-v` | `--version` | — | Print version. |
| — | `--rf`/`--rfunction` | name | Reflect a function. |
| — | `--rc`/`--rclass` | name | Reflect a class. |
| — | `--re`/`--rextension` | name | Reflect an extension. |
| — | `--rz`/`--rzendextension` | name | Reflect a Zend extension. |
| — | `--ri`/`--rextinfo` | name | Show an extension's configuration. |
| — | `--ini` | [diff] | Show config file names (`=diff` shows changed entries). |

### Common `./configure` switches

**Feature/SAPI toggles (`--enable-NAME`):**

```text
cli  cgi  fpm  embed  phpdbg  litespeed  opcache-jit  debug
debug-assertions  ipv6  dtrace  gcov  short-tags  fd-setsize
address-sanitizer  undefined-sanitizer  memory-sanitizer  werror
```

**Extension toggles — no external lib (`--enable-NAME`):**

```text
bcmath  calendar  ctype  dba  dom  exif  fileinfo  filter  ftp  gd
intl  mbstring  mbregex  mysqlnd  pcntl  pdo  phar  posix  session
shmop  simplexml  soap  sockets  sysvmsg  sysvsem  sysvshm
tokenizer  xml  xmlreader  xmlwriter  zend-test
```

**Extension toggles — link a system library (`--with-NAME[=DIR]`):**

```text
curl  openssl  zlib  bz2  zip  gmp  gettext  iconv  ldap  ldap-sasl
sodium  snmp  tidy  xsl  enchant  ffi  readline  libedit  libxml
mysqli  pgsql  pdo-mysql  pdo-pgsql  pdo-sqlite  sqlite3  pdo-odbc
pdo-firebird  pdo-dblib  freetype  jpeg  webp  avif  xpm  password-argon2
apxs2  capstone
```

**Build paths:**

```text
--prefix=PATH                      installation prefix (default /usr/local)
--with-config-file-path=PATH       directory PHP searches for php.ini
--with-config-file-scan-dir=PATH   extra directory of *.ini fragments
--with-layout=TYPE                 file layout (PHP or GNU)
--disable-all                      build minimal; add only what you enable
```

### Selected `php.ini` directives (production defaults)

| Directive | Default | Directive | Default |
|-----------|---------|-----------|---------|
| `engine` | `On` | `short_open_tag` | `Off` |
| `precision` | `14` | `serialize_precision` | `-1` |
| `output_buffering` | `4096` | `implicit_flush` | `Off` |
| `zend.enable_gc` | `On` | `zend.exception_ignore_args` | `On` |
| `expose_php` | `On` | `max_execution_time` | `30` |
| `max_input_time` | `60` | `memory_limit` | `128M` |
| `error_reporting` | `E_ALL & ~E_DEPRECATED` | `display_errors` | `Off` |
| `display_startup_errors` | `Off` | `log_errors` | `On` |
| `variables_order` | `"GPCS"` | `request_order` | `"GP"` |
| `post_max_size` | `8M` | `default_charset` | `"UTF-8"` |
| `enable_dl` | `Off` | `file_uploads` | `On` |
| `upload_max_filesize` | `2M` | `max_file_uploads` | `20` |
| `allow_url_fopen` | `On` | `allow_url_include` | `Off` |
| `default_socket_timeout` | `60` | `cli_server.color` | `On` |
| `session.save_handler` | `files` | `session.use_strict_mode` | `1` |
| `session.use_only_cookies` | `1` | `session.name` | `PHPSESSID` |
| `session.cookie_httponly` | `1` | `session.cookie_samesite` | `"Lax"` |
| `session.gc_maxlifetime` | `1440` | `session.cache_limiter` | `nocache` |

### Bundled SAPIs

```text
cli   cgi   fpm   phpdbg   embed   apache2handler   litespeed   fuzzer
```

### Useful links

- PHP language manual: [php.net/docs](https://www.php.net/docs)
- Installation guide: [php.net/install](https://www.php.net/install)
- Windows binaries: [windows.php.net](https://windows.php.net)
- Internal/implementation docs: [php.github.io/php-src](https://php.github.io/php-src/)
- Extension library: [PECL](https://pecl.php.net)
- Issues: [github.com/php/php-src/issues](https://github.com/php/php-src/issues)

---

_Generated June 2026 from php/php-src at 95b5b48. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
