An Exceptional Change in PHP 7.0

Project

With PHP 7 errors and exceptions are undergoing major changes. For the first time, the PHP engine will start to emit exceptions instead of standard PHP errors for (previously) fatal, and catchable fatal errors. This means that we can now handle them much more gracefully with try... catch.

But with this change, comes a whole new exception hierarchy:

At the top we now have an interface, \Throwable, which the original \Exception implements. Earlier versions did not have the interface and the root of the hierarchy was \Exception. We then have the new \Error exception, which is a sibling of \Exception as opposed to extending it, which also implements the new interface.

The reason \Error does not extend \Exception is so that the new exceptions will not get accidentally caught by legacy catch-all statements (catch (\Exception $e) { }) — and just like in older PHP versions, an uncaught exception is still a regular fatal error, preserving backwards compatibility.

If the ability to create a real catch-all is desired, you can catch the \Throwable interface. This means that to catch both regular exceptions, and engine exceptions, you would use catch (\Throwable $e) { } instead.

Error Exceptions

As you can see above, there are four new error exceptions, each one used for a different purpose:

\Error

Standard PHP fatal, and catchable-fatal are now thrown as \Error exceptions. These will continue to cause a “traditional” fatal error if they are uncaught.

\AssertionError

With PHP 7, we also have enhancements to assertions, using the assert() function, with the addition of zero-cost assertions, and the ability to have them throw exceptions. To enable this, you should simply set assert.exception to 1 in your php.ini (or via ini_set()).

These exceptions are (you guessed it) \AssertionError exceptions.

\ParseError

Thanks to error exceptions, you can now handle includes with parse errors, and eval() parse errors, as both now throw \ParseError exceptions:

\TypeError

With the introduction of scalar, and (especially) strict types in PHP 7, these will also throw exceptions when a type mis-match occurs. It is important to understand that this does not apply only to scalar type hints, but to traditional type hints such as class/interface names, callable and array.

Catchable Fatal Errors

Another important change in PHP 7 is with catchable fatal errors. Previously, these would have been caught and handled using set_error_handler(). However, with PHP 7, they are now \Error exceptions, which, because an uncaught exception is now a real fatal error, will no-longer be catchable in set_error_handler().

This is a backwards compatibility break and means that to work in both PHP 5.x and 7, you need to use both set_error_handler() and try... catch.

This is considered a minor BC break due to limited usage.

\Throwable and Userland

It would not be a big jump to conclude that now we have a common interface, we could create our own branches in the exception hierarchy for completely custom exceptions by simply implementing the \Throwable interface. Unfortunately, due to the fact that exceptions are magical under the hood, to be able to do things like capture line/file and stack trace information — this means that you still must still extend either \Exception or \Error, and cannot directly implement \Throwable alone.

Trying to implement \Throwable results in the following:

However, this is not the full story. You can extend \Throwable and then — while still extending \Error or \Exception — you can implement your extended interface:

Fin

As alluded to in the (pun intended) title of this post, these changes are actually quite big, allowing us to gracefully handle almost all previously fatal errors. The fact that the core team were able to maintain almost complete backwards compatibility while doing so is astounding. Kudos to them!

Class constants, how do they work? (Or: You Learn Something New Every Day…)

Project

Yesterday on Twitter there was a conversation started by Marco Pivetta regarding a particularly horrible bit of code he had spotted:

If it’s unclear, this creates a string using sprintf() by prefixing ::PARAMNAME with the result of calling get_class() on the $api variable, and then passes that string into constant() which will give you the value of a constant using it’s string name.

At which point Elizabeth Smith chimed in to point out that $api::PARAMNAME would not work in older versions of PHP, necessitating this horrible workaround.

I then added this to the conversation:

Turns out, I was wrong. Whoops. Trevor Suarez created a past on 3v4l.org showing that this did indeed work, going back to PHP 5.3 even.

Additionally, with PHP 7 — thanks to Uniform Variable Syntax — there are many more ways to achieve this too, as you can see below:

Now, obviously, a lot of these are facetious, I mean, who is going to do ['Foo'][0]::BAR, really? But it’s interesting to see just how consistent, and flexible the new Uniform Variable Syntax is.

The someFunction()::CONSTANT, SomeClass::method()::CONSTANT, and $obj->method()::CONSTANT are much more realistic, and likely to be something you will use at some point.

There were a few syntaxes that didn’t work, which on the one hand, I’m grateful for, but on the other, I think at least some of them should be possible. Presented without further comment:

As with everything in any programming language however:

just because you can do something, doesn’t mean you should

Use with caution.

Changes to Engine Exceptions in PHP 7.0alpha2+

Standard

Pre-Release Software

This blog post is about PHP 7.0 which at the time of writing is currently pre-release software (7.0.0alpha2) and subject to change.

While updating my PHP 7 talk “What to Expect When You’re Expecting: PHP 7″ for the DutchPHP Conference 2 weeks ago I noticed a small but significant change to the new Engine Exceptions feature in the newly release alpha 2.

Prior to alpha 2 and as per the Engine Exceptions RFC the exception hierarchy looked like this:

BaseException (abstract)
 ├── Exception extends BaseException
      ├── ErrorException extends Exception
      └── RuntimeException extends Exception
 └── EngineException extends BaseException
      ├── TypeException extends EngineException
      ├── ParseException extends EngineException
      └── AssertionError extends EngineException

The primary reason for doing this was to ensure two things:

  1. That \EngineException‘s didn’t get caught in pre-.7.0 catch-all blocks (i.e. catch (\Exception $e) { } to preserve backwards compatible behavior (fatal erroring appropriately
  2. That it was possible to build new catch-all blocks for all both old and new exceptions using catch \BaseException $e) { }

However, for alpha2 this hierarchy changed. Engine Exceptions lost their “Exception” suffix, and became \Error and and \*Error exceptions, and the abstract \BaseException class was changed to a \Throwable interface. This makes the new exception hierarchy look like this:

Throwable interface
 ├── Exception implements Throwable
      ├── ErrorException extends Exception
      └── RuntimeException extends Exception
 └── Error implements Throwable
      ├── TypeError extends Error
      ├── ParseError extends Error
      └── AssertionError extends Error

With these changes, you still cannot create your own exception hierarchy as you cannot implement \Throwable, you must still extend from \Exception or \Error exceptions (or their children), however you can extend \Throwable and (while still extending \Exception or \Error) implement that new interface.

Personally, I prefer this hierarchy, but, as with any pre-release software: everything is subject to change!

Edit:
As pointed out to me on Twitter, there is an RFC for this change: Throwable interface RFC

Farewell Engine Yard!

Standard

After almost 4 years at Engine Yard, my last day will be July 3rd.

It is a sad thing, but it also means I am moving on to hopefully bigger, exciting, more challenging, and better things.

On Saturday I gave my last conference talk as a Yardee, and I think it was fitting that it was about “What’s new in PHP 7″, as my first talk for Engine Yard was at PHPUK 2012 and it was about “What’s new in PHP 5.4″.

I have had an amazing time working for Engine Yard, learned a lot from lots of smart people, been able to travel the world and meet even more fabulous people. I have been allowed to shape my job around the life I want to lead: to be a good person, to teach and help people, and to spread the joy of the things I love to as many people as possible.

I will be moving on to Akamai Technologies on July 6th as a Developer Evangelist.

I will be working on some thing bigger than I can conceive and I’m excited at the prospect of helping people — particularly in the PHP community — to achieve amazing things using these tools and more.

But I wouldn’t be here if not for all I’ve been enabled to do the last four years:

Thank you Engine Yard ❤️

P.S.
Y’all should go check out Deis and Deis.com/Deis PRO, they’re pretty awesome!

Celebrating 20 Years of PHP

Standard

Twenty years ago today, Rasmus Lerdorf released Personal Home Page Tools (PHP Tools) version 1.0 to the world.

This is what Ben Ramsey tells us in his blog post celebrating 20 years of PHP.

Anyone who has talked to Rasmus knows that its popularity and success were all entirely accidental, and that he never planned for it to take over the world.

Except… it wasn’t really an accident was it?

Ben suggests that we all write about our own first encounters with PHP — I saw it on a Simpsons website, bought a book, pre-PHP 4.0, read three chapters, hacked on stuff, the rest is history — but I’d like to do something a little different. I want to tell our story.

As Erika Heidi points out in her blog post PHP powers about 80% of the web. Much of that (~25%1) is WordPress, including this blog.

That didn’t happen overnight, or accidentally. There were several factors that helped though:

  • PHP was easy to learn
  • mod_php made Apache2 integration fast, and easy
  • The MySQL extension made database access and use, fast, and easy3

The creation of great4 off-the-shelf software, like phpNuke, phpBB, phpMyAdmin, and the aforementioned WordPress, meant that end-users started to use PHP without even really understanding what it was… but they sure made a lot of software!

Even still, none of this was accidental, it was the result on a lot of hard work, by many thousands of people.

During my research for my talk, Open Source, Love, and Social Responsibility, I put together some numbers:

  • PHP is 1.5 million lines of code
  • Apache is 533,000 lines of code
  • MySQL is 3.4 million lines of code

All in all, a standard LAMP stack, those four little letters, amount to over sixty-nine and a half million (69,500,000) lines of code, which, more importantly were contributed by over 4800 people.

These days our skills as a community have risen dramatically since the days of phpNuke, we have amazing tools like composer, and PHPUnit. Four of the top ten websites are written in PHP.

Every single person who has used PHP, contributed to an open source PHP project, contributed to PHP, the docs, or even “just” been part of the community conversation: We are all responsible for this success.

So, think back, pat yourself on the back, and lets make things even better.

P.S.

If you’re interested in more PHP history, check out my blog posts on the history of PHAR files and ten years of PHP 5.0.0.


  1. That is, ~25% of the 80%, or ~20% of the web. 
  2. Yes, I know, it’s technically Apache httpd, deal with it. 
  3. Fast, easy, and insecure. Thank goodness for PHP 7: bye bye ext/mysql
  4. For the time. Our understanding of great software wasn’t itself very great in the 90’s.