Last week, I wrote about type hinting, in PHP. Type hinting makes the intent of a function clearer and forces the values to show a specific type of value.
While having a function that only accepts a certain type of value removes the need to check a variable’s type from the function, it doesn’t mean you don’t have to check that type first before calling the function. Passing a variable of the wrong type creates a fatal error.
For example, get_post_meta() can return pretty much any type of data. If you’re using it in a way that you expect it to return an array, you still must check that it returned the expected result. Therefore if you had a function that required an array for one of its parameters, you would need to check that you got a result of the expected type from get_post_meta(), not false or some other type.
If you could build an abstraction around get_post_meta() that was guaranteed to provide an array always, then you could safely pass its return value to a function that requires an array.
In PHP5 we can write functions that should always return an array, but we have no way to declare it programmatically as such. Yes, inline documentation helps humans and IDEs know what to expect. But that doesn’t help the compiler or guarantee results.
PHP7 introduces return type declarations, which allow us to do just that. A return type declaration makes it so a function’s return value must be of a specific type.
Pros And Cons Of Return Type Declarations
There are two major arguments for using return type declarations. The first is performance, which is directly affected because the return type is explicitly declared. This means that the PHP compiler does not have to figure it out, which in turn makes compiling faster.
The other argument for using return type declarations is similar to that for using type hinting: it makes the intent and expected usage of code for clear. Just like type hinting, you lose some of the flexibility that using a dynamically typed language provides. So, you must decide if it is worth trading that flexibility for clarity and possible performance gains.
Also, since return type hinting is not backwards compatible with PHP5, it’s not yet a good idea to use it in a WordPress plugin or theme that will be released publicly. Even if you were to build in version checks, WordPress.org does not allow plugins or themes to use syntax added in PHP 5.5 or later.
On the other hand, if you are working on a bespoke site that runs PHP7 and a PHP7 feature such as this is useful to you, why wouldn’t you use it?
An Example
In the introduction to this post I discussed the problems with relying on assuming that a function like get_post_meta() will always return an expected value. Even if you always put an array in a specific meta key, what happens if no data has been set for a specific post or if you try and get post meta for a non-existent post?
If your goal is to use a post meta value with a function that requires an array, in PHP5 you are forced to test the value returned by get_post_meta() every time. In PHP7 you could write an abstraction around get_post_meta() that not only ensured you were always getting back an array, but made it explicit through return type declarations.
Here is an example class that does just that:
<?php class get_post_meta { protected $post; public function __construct( WP_Post $post ) { $this->post = $post; } public function get_all() : array { return get_post_meta( $this->post->ID ); } public function get_key( $meta_key ){ $meta = get_post_meta( $this->post->ID, $meta_key ); if( ! is_array( $meta ) && ! empty( $meta ) ){ return [ $meta ]; }elseif ( empty( $meta ) ){ return []; }else{ return $meta; } } }
As you can see, we have two methods here that will always return an array. This is obvious to us as humans reading the code — if we know the new syntax. It is also will make for less code — no additional type checking code required — and will be faster for the PHP compiler to parse.
A New Syntax
Type hinting uses a new syntax that is not backwards compatible with PHP5. Here is a basic example of this syntax:
<?php function total_posts( WP_Query $query ) : int { return count( $query->posts ); }
In PHP5, this would generate a fatal error with this message:
Parse error: syntax error, unexpected ‘:’, expecting ‘{‘
In PHP7 this is interpreted as a return type declaration. Because the declaration is “int” this function has to return an integer or it will cause an error.
Here is an example, that uses type hinting and return type declarations to make a simple WordPress REST API client:
<?php class posts { protected $root; protected $posts; public function __construct( string $wp_root ) { $this->root = $wp_root; } public function query( int $page ){ $headers = array('Accept' => 'application/json'); $request = Requests::get( $this->root . 'posts/', $headers, [ 'page' => $page ]) ; $this->posts = json_decode( $request->body ); } public function get_total_posts() : int { if( empty( $this->posts ) || ! is_array( $this->posts ) ){ return 0; } return count( $this->posts ); } public function get_posts() : array { return $this->posts; } }
The last two methods in this class use return type declarations. The get_total_count() method uses an int type declaration and therefore must return an integer, while the get_posts() method uses an array return type declaration and therefore must return an array.
Keep in mind this example uses the Requests library, which is included in WordPress 4.6 or later.
Should You Use Return Type Declarations?
PHP became so popular because of how flexible and relatively easy it is to learn. A lot of that is due to the flexibility provided by dynamic typing. But this flexibility has limited PHP’s performance. PHP powers some of the most trafficked sites on the internet — WordPress.com, Facebook, Wikipedia, Etsy, and more. New language conventions that make PHP less flexible, but more performant are necessary to meet the challenges of using PHP at that scale.
Personally, I’m not making top 10 websites, but these new language constructs still matter to me. WordPress is awesome because of what it can do on a small server. The more performant our code is, the less server resources we need and that’s a big deal in the WordPress world, where code is expected to run on shared hosting and enterprise environments.
Our language is maturing and what we can do with it is very exciting. I hope that this article will inspire you to spin up a PHP7 powered WordPress site on your computer and start learning these exciting new features. They are not hard, but if you’re looking to improve your site’s performance and to be prepared for WordPress’ hopefully, eventual shift to embracing non-backwards compatible features of PHP7 learning PHP7 return type declarations is essential.
1 Comment