How to Choose a Minimum PHP Requirement

As a library developer I often face a problem what should be a minimum PHP requirement. Here are some of my principles.

1. Review what interpreter versions are suitable

Not all PHP versions are created equal. For example as a library developer I find the upcoming 8.3 release underwhelming and I will unlikely target it as a minimum dependency.

But that doesn't mean that as a "project developer" I would agree with that. Some projects I work with desire Randomizer::getBytesFromString() :D It goes without saying that you should try to use the latest release in your project and your libraries should support it too in their latest versions.

Still, let's review my subjective list of important features for a library author:

  • 8.3. Doesn't look like a target for me.

    • Typed class constants. Only if you allow some very specific inheritance.

    • #[Override]. A nice check but it only requires you to run tests in 8.3, not to make it a target version.

  • 8.2. (good target)

    • Readonly classes. Very important if you want to allow inheritance but also enforce immutability.

    • Randomizer. I try not to include features solvable by polyfills but userland randomizer is really slow.

    • #[SensitiveParameter]. Not really a reason to target 8.2 since the older versions will just ignore it while 8.2+ projects will enjoy an extra security feature.

  • 8.1. (favorite target)

    • Enums!

    • Readonly properties!

    • First class callable syntax: Closure::fromCallable($c) => $c(...)

    • Fibers may be useful for some niche libraries.

    • Final class constants.

  • 8.0. (good target)

    • The lowest non EOL-ed version of PHP (until next month).

    • mixed!

    • Union types. Better avoid them in general but sometimes they are very useful and sometimes even the only usable option.

    • match () {}

    • Named parameters. If only some future version makes named params enforceable like in Python...

    • Attributes!

    • Constructor property promotion. A nice syntax sugar.

  • 7.4. (favorite target) Last 7.x, a good target that can cover projects struggling with the upgrade to 8.x.

    • Typed properties. This feature makes 7.4 a very good target.

  • 7.3. Would be totally skippable if not for JSON_THROW_ON_ERROR.


    • Trailing commas.

    • Heredocs/Nowdocs can be indented.

  • 7.2. The current practical minimum because of Composer 2.3+. Otherwise unremarkable.

    • The lowest version that Composer beyond 2.2 LTS supports.

    • object type hint. I really used it once.

  • 7.1. (favorite target getting outdated) This is a version I targeted a lot and still may do it in future. Still, 7.4's typed properties are usually a must.

    • The lowest version that current Symfony polyfills support.

    • Nullable types. Sometimes I miss union types and mixed, but otherwise 7.1 makes most of the code properly typed.

    • Closure::fromCallable.

    • void return type.

    • Short list syntax. It makes me so much happier, but that's really minor.

    • iterable type hint.

  • 7.0. It was awesome when it was released but it's no longer a good target.

    • Abstract syntax tree made the language so much better that I just don't want to touch versions below that.

    • Scalar type declarations (but no nullable types)

    • Return type declarations (but no void)

    • ??.

    • <=>.

  • 5.6. (good target of the past) Last 5.x, a good target that can cover projects struggling with the upgrade to 7.x. Things get tricky here because supporting a library for 3 major PHP versions is a challenge by itself. It is also the lowest version where Composer 2.3+ autoloading works.

    • Splat operator.

    • use function and use const.

  • 5.5.

    • Generators.

    • ::class.

    • foreach ($a as list($x, $y, $z)) {}.

  • 5.4.

    • Traits (if you don't hate them).

    • $this in closures.

    • callable type hint.

    • Short array syntax. Like short list it makes me so much happier, but that's really minor.

  • 5.3. Absolute minimum. Features even don't matter here. Closures, namespaces, blah blah... The main thing here you should not go further below into a composer-less world. Just forget.

Of course there are many other points, like if you actively work with GD resources, it's better to be able to typehint them. That makes 8.0 a minimum for you where they were converted to classes.

Another case may be a dependency. For example psr/clock has 7.0 as a minimum requirement so making 5.x-compatible clock library is meaningless if interoperability is your goal.

2. Determine a competition category for the library

Here I divide libraries by possible competition. First, it's mainly about the first released version, you can always deprecate support later according to the packagist stats.

  • High competition. If there are other good implementations, aim for as high version as practical. Newer language features may allow you to design a better architecture.

    • arokettu/uuid where I can easily enforce immutable objects using 8.2 features.

  • Low competition or the library may be a base for other libraries. Aim for as low as practical, or even as low as possible. This way you can bring functionality to as many projects as possible.

    • arokettu/clock: when I wrote this library, no other psr/clock library worked under PHP 7, so I aimed at the minimal psr/clock requirement, PHP 7.0.

    • arokettu/is-resource: a solution to a very common problem created by resource to object migration. Since it's a very small and simple library, I pushed the minimum all the way back to PHP 5.3.

3. Don't suffer

There is no need to aim low when doing something really complex. arokettu/arithmetic-parser was a very complex task from the beginning so I saw no sense in targeting lower PHP versions. PHP 8.1 allowed me to build a much better architecture for the lib.


Comments powered by Disqus