decorative image for blog on php 8
November 12, 2020

Exploring PHP 8: New Features and Improvements

State of PHP
PHP Development

With PHP 8 coming out in the next few weeks, it’s important for teams to be aware of the new features and performance improvements.

In this blog, we look at some of these notable features and improvements in PHP 8, including the JIT compiler and the syntactical improvements that developers are sure to love.

PHP 8 Overview

As noted above, PHP 8 introduces a number of new features, functions, improvements, and deprecations to the language. The most talked about feature, of course, is the JIT compiler. While performance improving features like JIT deserve the limelight, the syntactical improvements may have more of a true impact for PHP practitioners – at least in the short term.

Release Date

While initially planned for release on November 26th, 2020, PHP 8 will now reach general availability in late Q4, 2020.

New Functions in PHP 8

PHP 8 introduces a handful of new functions, including:

  • str_contains
  • str_starts_with and str_ends_with
  • preg_last_error_msg
  • get_debug_type

For the purposes of this article, we’ll be focusing on the str_contains() function.

str_contains

There are a number of ways to find out if one string contains another. Generally, you’ll use strpos(). strpos() takes a haystack and the needle that you want to look for, and returns an integer indicating the first position at which the needle is found. Because it’s returning the position of one string in another, you can’t simply check for whether or not strpos() found it; if it returns zero (positions are zero-indexed and start with 0 instead of 1), then the conditional will treat it as a false value, indicating it wasn’t found.

This means you need to write the conditional as “strpos($haystack, $needle) !== false”, because false indicates that it could not find the position of the string. This is an esoteric, non-transparent way to look for a string in a string!

if (strpos('Foo Bar Baz', 'Foo') !== false) {
	     // FOUND
	}

To avoid this, PHP 8 introduces str_contains().  str_contains() returns a simple boolean indicating whether or not the needle is in the haystack, which is a lot easier to write, and, more importantly, understand as someone maintaining the code.

if (str_contains('Foo Bar Baz', 'Foo')) {
     	     // FOUND
	}

Engine Features and Changes in PHP 8

There are quite a few new engine features and changes in PHP 8. The headlining feature, of course, is the new JIT compiler.

  • JIT Compiler
  • Fatal errors on incompatible method signatures
  • LSP Enforcement
  • Resource "Classes“
  • Assertion behavior
  • XML-RPC is now in PECL
  • Reflection changes

For the purposes of this blog, I’ll be focusing on the JIT compiler (stay tuned for a deeper dive on JIT in PHP 8), resource “classes,” and reflection API changes.

JIT Compiler

The JIT compiler in PHP 8 is certainly the most talked about feature. While it is interesting, and does warrant a lot of the spotlight, the actual impact that the JIT compiler will have on PHP as a language is to be determined.

New Webinar: Exploring JIT in PHP 8

If you want more information on the JIT compiler, be sure to check out my upcoming webinar on JIT compilation in PHP 8. I’ll be talking about the nuts and bolts of the compiler, as well as what it may mean for PHP development going forward

See Webinar Details

Resource “Classes”

Resource “classes” are another big change in PHP 8. They serve as non-instantiable replacements for specific resource types. The available replacements include:

  • CurlHandle — curl_init() now returns CurlHandle, describing a curl resource.
  • GdImage — GdImage represents a GD resource, as returned by the various imagecreatefrom*() functions.
  • Socket / AddressInfo — Provided by the sockets extension; a number of the socket_*() functions return a Socket, and the socket_address_info_lookup() function returns an AddressInfo instance.

It’s also important to note that resources are no longer destroyed by functions like curl_close(). Instead, you have to unset() the instance in order to de-reference it because it's now a class instance.

What you gain is the ability to specify these classes as typehints in your methods and functions. Previously, you had to leave resource arguments or return values untyped, and document them via annotations; now you can have explicit types, making your code more readable, and more type-safe.

The trade-off is that you will now need to update your code to destroy resources using unset() instead of the previous functions used to destroy resources. This can generally be accomplished via search and replace.

Reflection API Changes

Another small, but important change in PHP 8 is the change to the Reflection API. When you’re using the attribute system (more on this later), you can now retrieve those attributes via the Reflection API on any other reflection classes. With the addition of union and mixed types, the ReflectionParameter methods getClass(), isArray() and isCallable() are now deprecated. This is because it’s much better to use getType(), which will give you the complete list of types that particular parameter satisfies.

PHP 8 Syntax Improvements

While JIT may be stealing the headlines, the syntactical improvements in PHP 8 offer big quality of life benefits for PHP developers. Whether that is in eliminating common boilerplate between the promoted constructor arguments, or the improved error and exception handling, there’s a lot for developers to be excited about.

  • Union Types
  • "mixed" pseudo type
  • Class Constructor property promotion
  • ::class ubiquity
  • Attributes
  • Match Expressions
  • Catch by type only
  • Throwing exceptions from expressions

For the purposes of this blog, we’ll be focusing on union types, match expressions, and attributes.

Union Types

Union types indicate that a value is one of two or more specified types. This is done with a vertical bar between each allowed type. For many developers who have been doing PHP annotations to specify your parameters or return values, you have probably been doing this already.

For those returning a lot of different types, or if you’re accepting a lot of different types, union types can make the code more complex and harder to understand. Still, there are a number of times where this will be very useful. For example, if you can accept a string, or an object implementing the new Stringable interface (“string|Stringable”), or if you can accept either an array, or an object implementing the Traversable interface (“array|Traversable”).

Match Expressions

Match expressions eliminate the guesswork associated with determining whether failure to break within a switch case is intentional or not, and simplify the common pattern of assigning a value based on a match.

When used, the value you pass to match() is going to be compared directly to whatever the expression is on the left-hand side. Whether that’s a value or an expression, the value you pass to match() must match it for it to be selected. When matched, the expression on the right is evaluated, and its return value returned; expressions can only be callables or a lambda functions, and no multi-line closures are allowed. 

Attributes

PHP 8 also integrates attributes at the language level. While attributes have been around for over 15 years via docblock annotations, having them built into the language provides better performance and more power, as well as more consistency (as annotation libraries have often supported different syntax varieties). We’ll likely see attributes being used widely in the development of rapid application development tooling.

Final Thoughts

On the whole, PHP 8 offers some big improvements. The syntactical improvements simplify a lot of common boilerplate, and the expansions to the type systems are wonderful.

JIT is an intriguing addition to the language, but we likely won’t start seeing the benefits until developers start writing libraries and applications that can truly take advantage of it.

Get Guidance and Support for Your Next Migration

If you’re considering migrating a large-scale application to PHP 8, our team can help answer questions you have and even provide support and assistance as you complete your migration. Click the button below to learn more.

See Migration Services

Additional Resources

Much of the content for this blog was pulled from my preparation for a recent webinar I did on PHP 8. The webinar looks at all of the features listed in this blog, and offers a closer look at some of the features I covered here today.

Want to learn more about how PHP has evolved from version to version? Be sure to view the resources below.