Historical note: In June 2011 I published an experimental fork of PHP 5.3.6. It was not a proposal for a production distribution or a branch I intended to maintain indefinitely. It was a working answer to a more interesting question: what would PHP look like if syntax experiments, specialized virtual-machine instructions, stricter defaults, and frequently needed helpers were tested together in the engine?
The source remains available in the infusion/PHP repository. The historical Patch import commit records the broad integration against the PHP 5.3.6 code base. This archival retrospective reads that source as an experiment from its time. It does not recommend running an unsupported PHP release today.
Why Fork the Language?
Most PHP extensions operate above the parser and virtual machine. They can add functions, but they cannot introduce literal syntax, alter string offsets, specialize an expression into a dedicated opcode, or remove old language behavior. A source fork made all of those layers available at once.
The project combined older patches with the contemporaneous Defcon and Infusion extension work, but the fork was a separate artifact. Those libraries remain independent projects and are not merged into this page. The fork itself touched the lexer and parser, compiler, Zend virtual machine, standard library, JSON implementation, MySQL native driver, SAPI boundary, and configuration system.
The release also attracted a substantial contemporary discussion. A Hacker News thread reached 92 points and debated syntax design, backwards compatibility, benchmarks, core versus extension boundaries, and whether such a large patch should have been split into smaller proposals. That response is useful historical context: the project was noticed, but many of its choices were intentionally provocative and not suitable for PHP unchanged.
Language and Compiler Experiments
Short array syntax
The parser accepted square brackets as an alternative to array(), including nested arrays and explicit keys:
$config = [
'host' => 'localhost',
'ports' => [80, 443],
]; This was a direct readability experiment. The same surface syntax later became part of PHP 5.4, independently of any claim about where the upstream work originated.
Binary integer literals
The lexer recognized 0b-prefixed binary integer literals. Bit masks could therefore be written in the notation that describes them most clearly:
$read = 0b0001;
$write = 0b0010;
$mode = $read | $write; Binary integer literal notation also appeared in PHP 5.4. As with short arrays, chronology establishes a later upstream equivalent, not a direct line of adoption from this fork.
Negative string offsets
String indexing was extended so that a negative offset counted backwards from the end. In the fork, $text[-1] selected the final byte and $text[-2] the preceding byte. This was deliberately byte-oriented, consistent with PHP strings at the time; it was not Unicode grapheme indexing.
$last = $text[-1];
// Equivalent byte-oriented expression in stock PHP 5.3:
$last = $text[strlen($text) - 1]; PHP 7.1 later standardized negative string offsets for the relevant string operations. The matching idea is notable, but the surviving record does not prove that the upstream implementation was derived from this patch.
Iteration and existence checks
The fork allowed foreach to iterate over the bytes of a string, yielding the numeric offset and one-byte value. It also added exists as a language construct distinct from isset: the experiment aimed to test whether a variable or property existed without treating a present null value as absent. Parser and VM changes also contain the related xifset experiment. These constructs never became PHP language syntax under those names.
if (exists($value, $object->property)) {
// Both storage locations exist; null is still a value.
}
foreach ($text as $offset => $byte) {
// Experimental byte iteration.
} Dedicated opcodes and constant folding
Calls to strlen() and count() were recognized by the compiler and emitted as dedicated opcodes instead of ordinary function calls. A call such as strlen('foo') could be folded to the constant 3 during compilation. The parser also emitted the built-in values true, false, and null directly rather than routing them through a normal constant lookup.
The original article reported large microbenchmark gains for isolated calls. Those numbers should not be treated as current performance guidance: they were measured against PHP 5.3-era dispatch costs, and a microbenchmark does not establish an application-level speedup. The durable idea was specialization. Modern PHP and OPcache perform broad families of call specialization, constant folding, and dead-code elimination, though not as evidence of a merge from this fork.
Internal string operations
Below the user-facing language, the patch optimized integer appends in PHP's internal smart_str buffer and added smart_str_append_const() for appending compile-time strings. It also replaced the per-call setup of a character-translation lookup table used by strtr() with precomputed data. These were local implementation changes rather than new PHP syntax, and their practical value depended on the surrounding PHP 5.3 code and compiler.
Runtime and SAPI Experiments
Cached request time
The patch replaced repeated kernel time queries in selected internal paths with the SAPI request timestamp. A use_sapi_time setting made that behavior optional. Companion lighttpd and nginx patches exported a RAW_TIME FastCGI variable because CGI itself had no standard channel for that cached value.
This optimization traded precision for fewer calls: a process running for more than a second could observe an old value. That makes it unsuitable as a transparent default for daemons and long-running requests. It should be read as a measurement-driven systems experiment, not as a generally safe clock API.
Output-buffer transfer
ob_fwrite() copied the active PHP output buffer to an open stream. It supported an experimental FastCGI response path in which PHP wrote a completed response to a tmpfs file and the web server delivered it with X-Sendfile. Stock PHP never acquired this function. The separate article on moving buffered PHP output through a file documents that server-side experiment and its limitations in detail.
Request and warning controls
The fork made construction of $_REQUEST optional through its variables-order handling and introduced ignore_include_warning for suppressing include warnings globally. Both ideas reduced recurring work or log noise, but both also changed observable runtime behavior. Current PHP offers narrower configuration and explicit application-level mechanisms; neither fork interface became a standard API.
Small core fixes
The patch set also enabled the existing chroot() path for FPM, added the private directive to the no-cache session limiter response, and made print_r(false) visibly represent the Boolean value instead of producing an empty string. These changes belong to the historical inventory, but they are independent maintenance fixes rather than evidence for the larger language-design experiments.
Library Additions
A large portion of the patch tested whether common application helpers belonged in the standard runtime. These were real C implementations rather than userland sketches:
| Function | Purpose in the fork |
|---|---|
str_random() | Generate a random string from a configurable alphabet. |
timechop() | Break a duration into selected calendar and clock units. |
xround() | Round an integer to a power-of-ten boundary. |
sigfig() | Round a number to a requested count of significant figures. |
sgn() | Return the sign of a number. |
strcut() | Shorten text without splitting the final word and append a marker. |
strcal(), strical() | Validate strings against a compact character-format notation. |
strmap() | Replace named placeholders in a template string. |
bround() | Round to a multiple of an arbitrary base. |
bound() | Clamp a value to a lower and optional upper bound. |
Existing functions were extended as well. strtr() could delete characters, implode() could join array keys, chr() accepted several code points, and microtime() returned a float by default. The default arguments of htmlspecialchars() favored UTF-8 and quote escaping. These changes reduced userland ceremony, but changing established defaults also made the fork source-incompatible with assumptions embedded in existing applications.
The JSON encoder gained JSON_CALLBACK_CHECK. Strings beginning with a special callback marker could be emitted without JSON quoting. That produced JavaScript-like object literals rather than valid JSON and would be an injection hazard if untrusted input reached the encoder. Modern code should keep data as valid JSON and attach executable behavior separately.
MySQL and Configuration Changes
The mysqlnd and MySQLi work enabled native numeric casting by default, made mysqli_fetch_all() favor associative rows, exposed matched-row counts, and added mysqli_return() as a one-value fetch-and-free helper. These choices optimized for terse application code, but several deliberately changed defaults and therefore could not be drop-in replacements for stock PHP behavior.
A second configuration file, php-global.conf, went much further. It could define or delete constants, mark variables as superglobals, and rename or delete functions and classes. That made the runtime surface deploy-time configurable, but it also made source inspection insufficient to know which language environment an application would receive. This remained one of the clearest fork-specific experiments.
Removal of Legacy Behavior
The fork removed or disabled a collection of features that were already widely regarded as liabilities: magic quotes, register globals, safe mode, ASP-style tags, call-time pass-by-reference, short open tags, and several older configuration controls, including define_syslog_variables and the function/class disable lists. It also lowered the default memory limit to 16 MB. This was less about adding syntax than testing how much simpler the runtime could become when backwards compatibility was not the primary constraint.
Parts of that cleanup direction were later superseded by upstream removals. PHP 5.4 removed magic quotes, register globals, safe mode, and call-time pass-by-reference. PHP 7.0 removed ASP tags. The exact sets and timelines differ, and the sequence alone is not evidence that PHP adopted the fork's patch.
Feature Status in Retrospect
The categories below describe observable outcomes, not provenance. Later standardized upstream means that PHP subsequently exposed substantially the same user-facing idea. Conceptually similar upstream means PHP later solved a related problem through a different interface or implementation.
| Status | 2011 experiments | Later PHP position |
|---|---|---|
| Later standardized upstream | Short array syntax and binary integer literals | Both became language features in PHP 5.4. |
| Later standardized upstream | Negative string offsets | Supported upstream in PHP 7.1. |
| Conceptually similar upstream | Dedicated opcodes, compile-time evaluation, and reduced call overhead | The PHP engine and OPcache later developed much broader specialization and optimization machinery. |
| Conceptually similar upstream | str_random() | PHP 7.0 added random_bytes(); it solves secure byte generation without copying this API. |
| Superseded | Early removal of magic quotes, register globals, safe mode, call-time references, and ASP tags | Upstream removed overlapping legacy features across PHP 5.4 and PHP 7.0. |
| Fork-specific | exists, xifset, string foreach, and the altered function defaults | No compatible language surface was standardized under these names and semantics. |
| Fork-specific | ob_fwrite(), php-global.conf, JSON_CALLBACK_CHECK, and the helper set | These remained local runtime and library experiments. |
What the Fork Demonstrated
The strongest ideas were small and composable: compact literals, indexing from the end of a string, constant folding, and specialized execution paths for operations the compiler can recognize. They improve the language without asking deployment configuration to redefine what ordinary source code means.
The weakest ideas blurred data and code, silently changed established defaults, or optimized around infrastructure assumptions. Unquoted callbacks in JSON, globally renamed functions, cached request time, and server-specific FastCGI variables all made a local task easier by increasing system-wide surprise.
That contrast is why the fork remains worth documenting. It was a concrete R&D branch, not merely a wish list: the source records which layers had to change, which conveniences created compatibility costs, and which experiments later resembled durable language features. Similarity to later PHP is historically interesting; attribution requires evidence that the surviving repository and public record do not provide.
References
- [Fork]Robert Eisele. Experimental PHP 5.3.6 fork, 2011.
- [Patch]Robert Eisele. Patch import, June 8, 2011.
- [PHP54]PHP Documentation Group. Migrating from PHP 5.3.x to PHP 5.4.x: New features.
- [PHP71]PHP Documentation Group. Migrating from PHP 7.0.x to PHP 7.1.x: New features.
- [PHP70]PHP Documentation Group. Migrating from PHP 5.6.x to PHP 7.0.x: Backward-incompatible changes.