Platform.sh: Watch your inheritance

Watch your inheritance
Crell
Mon, 12/11/2020 – 21:39

Blog

PHP 7.2 introduced a neat new feature called “type widening”. In short, it allows methods that inherit from a parent class or interface to be more liberal in what they accept (parameters) and more strict in what they return (return values) than their parent. In practice they can only do so by removing a type hint (for parameters) or adding one where one didn’t exist before (return values), not for subclasses of a parameter. (The reasons for that are largely implementation details far too nerdy for us to go into here.) Still, it’s a nice enhancement and in many ways makes PHP 7.2 more compatible with earlier, less-typed versions of PHP than 7.0 or 7.1 were.

There’s a catch, though: Because the PHP engine is paying more attention to parameter types than it used to, it means it’s now rejecting more invalid uses than it used to. That’s historically one of the main sources of incompatibilities between different PHP versions: Code that was technically wrong but the engine didn’t care stops working when the engine starts caring in new version. Type widening is PHP 7.2’s case of that change.

Consider this code:

interface StuffDoer {
public function doStuff();
}

class A implements StuffDoer {
public function doStuff(StuffDoer $x = null) {}
}

This is nominally valid, since A allows zero parameters in doStuff(), which is thus compatible with the StuffDoer interface.

Now consider this code:

class A {
public function doStuff(StuffDoer $x = null) {}
}

class B extends A {
public function doStuff() {}
}

While it seems at first like it makes sense, it’s still invalid. We know that B is going to not do anything with the optional $x parameter, so let’s not bother defining it. While that intuitively seems logical the PHP engine disagrees and insists on the parameter being defined in the child class, even though you and I know it will never be used. The reason is that another child of B, say C, could try to re-add another optional parameter of another type; that would technically be compatible with B, but could never be compatible with A. So, yeah, let’s not do that.

But what happens if you combine them?

interface StuffDoer {
public function doStuff();
}

class A implements StuffDoer {
public function doStuff(StuffDoer $x = null) {}
}

class B extends A {
public function doStuff() {}
}

There’s two possible ways to think about this code.

B::doStuff() implements StuffDoer::doStuff(), which has no parameters, so everything is fine.
B::doStuff() extends A::doStuff(), which has a parameter. You can’t leave off a parameter, so that is not cool.
Prior to PHP 7.2, the engine implicitly went with interpretation 1. The code ran fine. As of PHP 7.2.0, the engine now uses interpretation 2. It has to, because it’s now being more careful about when you’re allowed to drop a type on a parameter in order to support type widening. So this wrong-but-working code now causes a fatal error. Oopsies.

Fortunately, the quickfix is super easy: Just be explicit with the parameter, even if you know you’re not going to be using it:

interface StuffDoer {
public function doStuff();
}

class A implements StuffDoer {
public function doStuff(StuffDoer $x = null) {}
}

class B extends A {
public function doStuff(StuffDoer $x = null) {}
}

The more robust fix is conceptually simpler: Don’t do that. While adding optional parameters to a method technically doesn’t violate the letter of an interface, it does violate the spirit of the interface. The method is now behaving differently, at least sometimes, and so is not a true drop-in implementation of the interface.

If you find your code is doing that sort of stealth interface extension, it’s probably time to think about refactoring it. As a stopgap, though, you should be able to just be more explicit about the parameters in child classes to work around the fatal error.

Enjoy your PHP 7.2!

Larry Garfield

13 Dec, 2020


Source: New feed

This article was republished from its original source.
Call Us: 1(800)730-2416

Pixeldust is a 20-year-old web development agency specializing in Drupal and WordPress and working with clients all over the country. With our best in class capabilities, we work with small businesses and fortune 500 companies alike. Give us a call at 1(800)730-2416 and let’s talk about your project.

FREE Drupal SEO Audit

Test your site below to see which issues need to be fixed. We will fix them and optimize your Drupal site 100% for Google and Bing. (Allow 30-60 seconds to gather data.)

Powered by

Platform.sh: Watch your inheritance

On-Site Drupal SEO Master Setup

We make sure your site is 100% optimized (and stays that way) for the best SEO results.

With Pixeldust On-site (or On-page) SEO we make changes to your site’s structure and performance to make it easier for search engines to see and understand your site’s content. Search engines use algorithms to rank sites by degrees of relevance. Our on-site optimization ensures your site is configured to provide information in a way that meets Google and Bing standards for optimal indexing.

This service includes:

  • Pathauto install and configuration for SEO-friendly URLs.
  • Meta Tags install and configuration with dynamic tokens for meta titles and descriptions for all content types.
  • Install and fix all issues on the SEO checklist module.
  • Install and configure XML sitemap module and submit sitemaps.
  • Install and configure Google Analytics Module.
  • Install and configure Yoast.
  • Install and configure the Advanced Aggregation module to improve performance by minifying and merging CSS and JS.
  • Install and configure Schema.org Metatag.
  • Configure robots.txt.
  • Google Search Console setup snd configuration.
  • Find & Fix H1 tags.
  • Find and fix duplicate/missing meta descriptions.
  • Find and fix duplicate title tags.
  • Improve title, meta tags, and site descriptions.
  • Optimize images for better search engine optimization. Automate where possible.
  • Find and fix the missing alt and title tag for all images. Automate where possible.
  • The project takes 1 week to complete.