PHP went from 5.6 to 7.0 in December 2015. If you started with PHP after that, you might not know there ever was a PHP 6.
There was. Core developers worked on it for about five years. Its lead developer spoke about it at conferences, and publishers sold books about it. Then in March 2010, the project was shelved, and in 2014, PHP internals voted 58 to 24 to skip the number entirely.
One small piece of it is still in PHP today, and as of this month, internals is talking about removing it. Here's the story on what PHP 6 was supposed to be, why it failed, and why the next version was called 7.
The Problem PHP 6 Was Meant to Solve
In PHP, a string is a sequence of bytes. PHP doesn't know or care what encoding those bytes are in. That's fine for plain English text, where one letter is one byte. It stops being fine as soon as you leave ASCII:
echo strlen('café'); // 5
In UTF-8, é takes two bytes, so strlen() counts five. Functions like substr() and strtoupper() have the same problem, since they work on bytes, not characters. Cut a UTF-8 string in the wrong place and you get broken text.
We worked around this with extensions like mbstring and its mb_ functions. But the language itself had no idea what a character was.
In August 2005, Andrei Zmievski put it bluntly in his design document for fixing it:
As successful as PHP has proven to be in the past several years, it is still the only remaining member of the P-trinity of scripting languages - Perl and Python being the other two - that remains blithely ignorant of the multilingual and multinational environment around it.
The Plan
According to Andrei's later talk on the project, he launched the Unicode effort at Yahoo in February 2005, with a small group from Yahoo, Zend, and the PHP community. The work was "initially slated for 5.x," but the changes grew big enough to need a major version.
His design document, posted to internals on August 10, 2005, laid out the approach:
- ICU. PHP would use the International Components for Unicode library for Unicode support.
- UTF-16 inside. Unicode strings would be stored as UTF-16 internally, because ICU used UTF-16 for its own processing.
- A switch. A
unicode_semanticssetting would turn Unicode mode on for a whole site. - Two kinds of strings. Text would be Unicode by default, and raw bytes would get their own binary type. A
bprefix, as inb"...", would mark a binary string literal.
The design document explained the UTF-16 choice:
While being less memory efficient for basic ASCII text it simplifies the processing and makes interfacing with ICU easier, since ICU uses UTF-16 for its internal processing as well.
That decision would come back to haunt the project.
The next day, Andrei warned everyone that the Unicode code was about to land in the main branch:
The warning goes into full effect now: do not commit anything to Zend/, main/, or ext/standard/ or I will hunt you down and make you memorize the entire contents of Unicode Character Set. In binary.
The first "Unicode support" commits went into php-src late on August 11, 2005. The day after, Rasmus Lerdorf started a wishlist thread for the new version:
Since we are breaking a lot of stuff in 6.0, at least with Unicode_semantics=On I am wondering if it may not be time to break some more stuff and do a bit of spring cleaning.
The Paris Meeting
In November 2005, core developers met in Paris to plan PHP 6. The group included Rasmus, Andrei, Derick Rethans, Zeev Suraski, Dmitry Stogov, Marcus Börger, Wez Furlong, and Jani Taskinen. Derick published the minutes.
PHP 6 got a long list of decisions:
- Unicode mode would be controlled by a php.ini switch that defaulted to on.
- Extensions that weren't updated for Unicode wouldn't load in Unicode mode.
- register_globals, magic_quotes, and safe_mode would be removed.
- An opcode cache, APC, would be bundled.
- Namespaces, late static binding with
static::, and a 64-bit integer type would be added.
The minutes also recorded an early warning sign:
current micro benchmarks show that the Unicode implementations of some of the string functions are up to 300% slower, and whole applications up to 25% slower.
Building It
Work continued in php-src's main branch, which was now PHP 6. Andrei renamed the switch to unicode.semantics in 2006, and Dmitry committed namespaces to the PHP 6 branch in 2007.
PHP 5 got a small piece of the future too. In PHP 5.2.1, released in February 2007, the NEWS file listed "forward support" for the b string prefix and a (binary) cast. The idea was that you could start marking binary strings in PHP 5 code so it would be ready for PHP 6:
$bytes = b"\x89PNG"; $data = (binary) $input;
In PHP 5, a b string was an ordinary string, and (binary) was an alias of (string). They were placeholders for a version that hadn't shipped yet.
Over time, developers started asking whether a Unicode on/off switch made sense at all, since code would have to work both ways. In May 2008, Andrei removed it with this commit message:
Crossing the Rubicon: remove the unicode.semantics switch and default unicode mode to On.
PHP 6 was now Unicode, full stop.
PHP 5.3 Takes the Features
Meanwhile, PHP 6 was taking a long time, and the other features planned for it were done.
In September 2007, Ilia Alshanetsky proposed a feature list for a PHP 5.3 release. The first item was "Backport the namespaces patch for PHP 6." Developers voted in favor of backporting namespaces, late static binding, and __callStatic from PHP 6.
PHP 5.3.0 shipped on June 30, 2009, with namespaces, late static binding, closures, goto, and the short ternary ?:. It also brought in intl, an extension that wrapped ICU for things like formatting dates and numbers by locale, and worked with PHP 5.
That left PHP 6 with one big feature. A slide in Andrei's talk summed it up:
PHP 6 = PHP 5 + Unicode
The Books
While all of this was happening, publishers were printing books about PHP 6.
- PHP 6 and MySQL 5 for Dynamic Web Sites, by Larry Ullman, from Peachpit in December 2008
- PHP 6 and MySQL 6 Bible, by Steve Suehring, Tim Converse, and Joyce Park, from Wiley in 2009
- Professional PHP6, from Wrox in 2009
- Beginning PHP 6, Apache, MySQL 6 Web Development, from Wrox in 2009
None of the versions in those titles ever shipped. MySQL 6 didn't either.
It's easy to blame the authors, but the 2014 naming RFC pushed back on that. It said PHP 6 was "taught to users as a done-deal, including detailed explanations about features and behavior (by php.net developers, not 'evil' book authors)." Andrei's own slides list "Spoke at multiple conferences about the project" among the things that went right. Rasmus saw it differently in 2010:
People who have written books or articles about PHP 6 inferring they knew what the final state of PHP 6 would be were misguided. We never got to the point of a final feature set much less a release date.
Why It Stalled
The core problem was the choice of UTF-16.
The outside world mostly speaks UTF-8. Files, databases, and HTTP all use it. So every time PHP 6 talked to anything outside itself, it had to convert. Pierre Joye explained in 2010:
The win we may have from using UTF-16 is almost completely lost by the conversions cost.
Stas Malyshev listed performance and compatibility as the two biggest problems. Many extensions people relied on, like mysql and pcre, didn't handle UTF-16 well, and "inflated memory usage hurts scalability a lot." Existing apps could break in strange ways, including cases "where your passwords suddenly stop working because there's an extra recoding step in some md5() call."
There was also a people problem. Converting every extension to the new string types was slow, tedious work. Johannes Schlüter, the PHP 5.3 release manager, wrote that it led to "many contributors not willing to use 'trunk' as their main development tree but either develop using the stable 5.2/5.3 trees or refuse to do development at all."
Andrei was candid about it in his 2011 talk, "The Good, The Bad & The Ugly: What Happened to Unicode and PHP 6." His slides said there were "Probably <10 people who understood the intricacies of the Unicode and ICU," and that "People were bored converting large chunks of already working code." Looking back, he said he "Would probably choose UTF-8, if started over."
March 11, 2010
PHP 6 ended with an argument about output buffering.
On March 11, 2010, Jani Taskinen merged a large output buffering change into the stable PHP 5.3 branch. When people objected that it didn't belong in 5.3, he replied:
Yadda yadda, it's a bug fix. Just call next one 5.4 like it should be.
Derick's response was short: "No, put that stuff in 6!" A few hours later, Jani created a PHP 5.4 branch himself. The commit message was "Hello PHP 5.4, open for all new stuff."
That forced the question. An hour later, Rasmus sent an email with the subject line "PHP 6":
Ah, Jani went a little crazy today in his typical style to force a decision. The real decision is not whether to have a version 5.4 or not, it is all about solving the Unicode problem. The current effort has obviously stalled.
He continued:
We knew the Unicode effort was hugely ambitious the way we approached it. There are other ways.
Rasmus proposed moving the PHP 6 code to a branch, moving development back to the main line, and looking for "lighter and more approachable ways to attack Unicode," pointing to mbstring and ext/intl. He also ruled out running two development lines at once again:
I refuse to go down the path of a 5.4 branch and a separate Unicode branch again.
Jani was frustrated by how decisions got made. In another message that day, he suggested renaming the PHP 6 branch to THIS_IS_LOST_CAUSE, and wrote, "I'm just sick and tired of the cloak and dagger style and secret meetings and committees."
On March 16, Derick did the renaming. He announced:
I've just renamed the 5.4 branch to THE_5_4_THAT_ISNT_5_4 and moved trunk to the branch FIRST_UNICODE_IMPLEMENTATION.
You can still find both branches in the php-src repository on GitHub, as experimental/first_unicode_implementation and experimental/the_5_4_that_isnt_5_4.
In his 2011 talk, Andrei put a "TIME OF DEATH" slide on the moment Jani created the 5.4 branch. He also explained why he didn't try again: "Invalidation of several man-years of hard work is discouraging," and he "Did not feel like pushing the project up the hill again."
The Years Without a 6
PHP moved on without it. PHP 5.4 shipped in March 2012 with traits, the short [] array syntax, and the built-in web server. It also finally removed register_globals, magic quotes, and safe mode, all things the Paris meeting had planned for PHP 6. PHP 5.5 followed in 2013, then 5.6 in 2014.
The php.net manual's history page sums up where PHP 6's features went:
This work was later abandoned, but other features that had been targeted for PHP 6 were instead incorporated into PHP 5.3 (namespaces) and PHP 5.4 (trait, "short" array syntax).
Nobody had decided what the next major version would be called, though. In 2012, Anthony Ferrara started a thread about a future 6.0, noting that "all progress on that has stopped for quite some time." In 2013, php-src's main branch was labeled 5.7, not 6.
By early 2014, people were once again talking about "PHP 6," now meaning a new major version without the Unicode rewrite. Rasmus described what a better Unicode attempt would need: a small, fast library "using UTF-8 as its internal storage so we don't have to convert on each and every operation."
Not everyone wanted the old name. In April 2014, Eli White asked internals not to use it:
We should not name the next version of PHP: PHP6, for 2 reasons: 1. It will cause confusion in those least able to adapt 2. It costs us nothing, hurts us in no way, to name it something else
He offered alternatives, including "PHP 2014" and "PHP Leaping Leopard." Zeev replied "+1 on PHP 7.0." Nikita Popov disagreed:
If it's PHP 7, this will lead to confusion about a version number being skipped. (Which is imho a pretty big wtf moment.)
PHPNG
What finally gave the next version a reason to exist was speed.
In May 2014, Dmitry Stogov announced phpng, a refactored Zend Engine he'd been working on for four months with help from Xinchen Hui and Nikita. He described the approach this way: "we changed the basement trying to keep most of the building unchanged." His early numbers showed 10 to 30% speedups on real applications. In a later RFC, he and Zeev claimed gains "anywhere between 20% and 110%" on apps like WordPress and Drupal.
In August 2014, internals voted 47 to 2 to make phpng the base for the next major version.
The Naming Vote
The naming question went to a vote first.
In July 2014, Andrea Faulds opened the Name of Next Release of PHP RFC. It started as a yes or no on PHP 6. Zeev asked for a real choice between 6 and 7, and became a co-author to write the case for 7.
The case for 7 started with history:
First and foremost, PHP 6 already existed and it was something completely different. The decimal system (or more accurately the infinite supply of numbers we have) makes it easy for us to skip a version, with plenty more left for future versions to come.
It argued that version 6 had bad associations: "PHP 6 was a failure; Perl 6 was a failure," and MySQL 6 never shipped either. It also made the risk argument:
Taking a risk that stands to yield absolutely no reward is not a good strategy.
And it added a joke: "As a special non serious bonus, 7 is perceived as a lucky number in both the Western world and Chinese culture."
The case for 6 was about consistency. "According to our current release process and semantic versioning, the next major version after PHP 5 should be PHP 6." Books that promised features PHP 6 didn't have would get bad reviews and fade away. It also had a joke of its own: if PHP really needed a distinct name, "The existing precedent suggests going to PHP 2016 or something equally distinct, rather than just skipping a version. (No, this is not a serious suggestion.)"
The vote got messy. When voting opened, Zeev asked for a pause and rewrote the case for 7. Andrea then canceled the vote, saying the RFC had become unbalanced. Derick objected: "This is like you weren't happy with the way how the vote was going so you cancelled it? What nonsense." Nikita said Zeev's edits had removed arguments for 6, and called it "discourteous and disingenuous."
The vote restarted on July 23. Andi Gutmans, a co-creator of the Zend Engine, weighed in on the Perl 6 comparison:
It feels pretty obvious to me that we are doing people a disservice calling it PHP 6.
On July 29, 2014, Andrea announced the result: "By 58 votes to 24," the next version would be PHP 7. Andrea, Nikita, Phil Sturgeon, Levi Morrison, and Pierre Joye were among those who voted for 6. Zeev, Andi, Dmitry, Xinchen Hui, Derick, Stas, Sebastian Bergmann, and Fabien Potencier voted for 7. Rasmus didn't vote.
Andrea closed the thread with relief:
Hopefully this is the end of the matter and we can get onto matters of implementation and features, rather than naming. :)
Phil Sturgeon summed up the debate in a blog post titled "The Neverending Muppet Debate of PHP 6 v PHP 7." His view of the two sides: "One side has a lot of reasons, the other just has the one: 5 + 1 = 6."
A few weeks later, on August 15, Dmitry bumped the version in php-src to 7.0.0-dev. A PHP 5.7 RFC was declined that winter, so 5.6 became the last PHP 5.
PHP 7.0
PHP 7.0.0 shipped on December 3, 2015. The announcement said "PHP 7 is up to twice as fast as PHP 5.6." It added scalar type declarations, return type declarations, the ?? operator, the <=> spaceship operator, and anonymous classes. It also removed old extensions like ereg and the original mysql extension.
Zeev called it "the first major version of PHP in over a decade." Rasmus told InfoWorld, "On most real-world applications, you'll get a 100 percent speedup."
PHP 7 didn't have native Unicode strings. It still doesn't. Strings in PHP are still bytes, and you still reach for mbstring or intl when characters matter.
What's Left of PHP 6
A few traces of PHP 6 are still around.
- The
bprefix and(binary)cast. Both still exist. The prefix still makes an ordinary string, and(binary)is still an alias of(string). An RFC to deprecate them failed in 2017, 19 to 13, short of the two-thirds it needed. The(binary)cast was deprecated in PHP 8.5 along with other non-standard cast names. - The
bprefix, again. In September 2026, Juliette Reinders Folmer proposed deprecating it, noting that it and the cast "were both introduced in PHP 5.2.1 for forward compatibility with PHP 6." It's now on the list of planned PHP 8.7 deprecations. - intl. The intl extension, which brought ICU to PHP 5.3, is still how PHP handles locale-aware formatting, collation, and more. Andrei's talk listed it among the things that went right.
- The branches. The original Unicode implementation still sits in php-src as an experimental branch.
In February 2018, Nikita removed the last checks for the unicode.semantics setting from php-src.
PHP 6 is a strange thing to have in a language's history: a version that was planned, built, written about, and taught, and then never released. The work wasn't wasted. Most of its features shipped in PHP 5.3 and 5.4, a little later than planned. The one feature that didn't ship is the reason the number is gone.
Timeline
- Feb: Andrei Zmievski starts the Unicode project at Yahoo.
- Aug 10: Andrei posts the PHP Unicode design document to internals.
- Aug 11: The first Unicode support commits land in php-src.
- Nov 11: The Paris developer meeting plans PHP 6.
- Feb 08: PHP 5.2.1 adds the
bprefix and(binary)cast for forward compatibility with PHP 6. - Sep: Internals votes to backport namespaces and other PHP 6 features to PHP 5.3.
- May 19: Andrei removes the Unicode switch. PHP 6 is Unicode only.
- Jun 30: PHP 5.3.0 ships with namespaces, closures, and late static binding.
- Mar 11: Jani Taskinen creates a PHP 5.4 branch. Rasmus proposes shelving the Unicode work.
- Mar 16: Derick moves PHP 6 to the
FIRST_UNICODE_IMPLEMENTATIONbranch. - Apr 22: Andrei gives "What Happened to Unicode and PHP 6."
- Mar 01: PHP 5.4.0 ships with traits and short array syntax.
- May 05: Dmitry Stogov announces phpng.
- Jul 29: Internals votes 58 to 24 to name the next version PHP 7.
- Aug 15: php-src's version is bumped to 7.0.0-dev.
- Dec 03: PHP 7.0.0 ships.
- Feb: An RFC to deprecate the
bprefix and(binary)cast is declined. - Feb 03: The last
unicode.semanticschecks are removed from php-src. - Sep 25: Juliette Reinders Folmer proposes deprecating the
bprefix.
Read More
- Name of Next Release of PHP RFC
- The Good, The Bad & The Ugly: What Happened to Unicode and PHP 6 by Andrei Zmievski
- PHP Unicode support design document from 2005
- Minutes of the 2005 Paris developer meeting
- Rasmus Lerdorf's "PHP 6" email from March 2010
- Future of PHP 6 by Johannes Schlüter