phar-io/version: ~1.0 without a patch level means ^1.0, not a minor lock
Library for handling version information and constraints
At a glance
- What is it?
- phar-io/version is a small PHP library for version numbers and version constraints: parse a constraint string, then ask whether a version complies. It covers the caret and tilde operators with the precision you would expect from a semver implementation, and it has one sharp edge that catches everyone once. The other fact worth knowing is administrative: the newest release is 3.2.1 from February 2022, while the branch was pushed as recently as 2026-05-20.
- Who is it for?
- Adopt it when you need to assert a version range in PHP and want the semantics spelled out rather than guessed, especially if you are writing tooling that validates released artefacts. Do not adopt it expecting dependency resolution, because complies() answers a yes or no question and never picks a version for you.
- Can I use it commercially?
- Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 178 days ago.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.
Star history
- phar-io/version7,462 ★ · -1
| Repository | 2026-09-22 | 2026-11-13 |
|---|---|---|
| phar-io/version | 7.5k | 7.5k |
-1 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
~1.0 without a patch level is identical to ^1.0
This is the detail to internalise before you write a single constraint. The tilde operator's behaviour depends on whether a patch level version is provided or not, and if no patch level is provided the tilde operator behaves like the caret operator. In the project's own terms, `~1.0` is identical to `^1.0`. The consequence is the difference between a minor-version lock and a major-version lock, decided by two characters you may have typed out of habit. If you wanted every version inside minor version 1.1, `~1.0` will not give it to you; it will accept the whole of major version 1. The fix is small, and it is exactly what the documentation says: write the patch level. `~1.0.0` is a minor lock, `~1.0` is a major lock wearing the same punctuation.
Both operators are just ranges written the long way
The two special operators are defined as expansions, and reading the expansions is the quickest way to understand them. The caret operator `^1.0` can be written as `>=1.0.0 <2.0.0` and read as every Version within major version `1`. The tilde operator `~1.0.0` can be written as `>=1.0.0 <1.1.0` and read as every version within minor version `1.1`. So the caret is a major-version range and the tilde with a patch level is a minor-version range, which is the mental model you want. The library also supports the ordinary mathematical operators such as `<=` and `>=`, since a constraint may describe a discrete version number as well as a range. Version numbers themselves follow the semantic versioning schema of `<major>.<minor>.<patch>`, which is what makes the expansions well defined.
complies() is a predicate, not a resolver
The whole API is small enough to read at a glance, and its shape matters for how you use it. You build a `VersionConstraintParser`, call `parse` on a constraint string, and then call `complies` on a `Version`:
use PharIo\Version\Version;
use PharIo\Version\VersionConstraintParser;
$parser = new VersionConstraintParser();
$caret_constraint = $parser->parse( '^7.0' );
$caret_constraint->complies( new Version( '7.0.17' ) ); // true
$caret_constraint->complies( new Version( '7.1.0' ) ); // true
$caret_constraint->complies( new Version( '6.4.34' ) ); // falseWhat it does not do is choose. There is no call that returns the newest complying version, no sorting helper presented as the main event, and no resolver interface in the examples. So the library answers one question, does it correctly, and leaves the decision of what to install to you or to Composer. That is a reasonable division of labour for a small library, and it is also why it fits inside a test suite as easily as inside a release script.
The tilde example shows the minor lock working as advertised
The second half of the usage example is worth reading next to the first, because the two constraints differ only in the patch level and the results differ accordingly:
$tilde_constraint = $parser->parse( '~1.1.0' );
$tilde_constraint->complies( new Version( '1.1.4' ) ); // true
$tilde_constraint->complies( new Version( '1.2.0' ) ); // falseA patch bump inside 1.1 complies; the next minor does not. Compare that with the caret example above, where 7.1.0 complies against `^7.0`. Two constraints, two different notions of stability, both behaving as documented. If you are writing constraints in a script or a test, this pair is the cheapest way to check your own understanding, and if a test of yours disagrees with these results, the thing to re-read is the patch level rather than the library.
Pre-release ordering arrived in 2.0.0 and changes comparison results
There is one behaviour change in the project's history that affects anyone upgrading, and it is stated in a single line: as of version 2.0.0, pre-release labels are supported and taken into account when comparing versions. The demonstration is two alpha builds of the same release:
$leftVersion = new PharIo\Version\Version('3.0.0-alpha.1');
$rightVersion = new PharIo\Version\Version('3.0.0-alpha.2');
$leftVersion->isGreaterThan($rightVersion); // false
$rightVersion->isGreaterThan($leftVersion); // trueThe labels order correctly, which is the point. If your code compared versions before 2.0.0 and treated pre-release strings as opaque, results can differ after upgrading, so pin 2.0.0 or later and check any ordering assertion you rely on. The comparison methods here are `isGreaterThan` on a Version rather than on a constraint, which is a second, separate entry point worth knowing exists.
The newest release is from 2022 and the branch is not
The administrative picture is worth one paragraph because it affects how you pin. The release list is 3.2.1 published 2022-02-21, 3.1.1 from 2022-02-07 and 3.1.0 from 2021-02-23. The repository is not archived, and the last push is dated 2026-05-20. So commits are landing while no release has been cut since early 2022. For a dependency whose job is comparing strings and integers, that is a low-risk gap: the API in the README is two classes and one predicate, and nothing in the tree suggests a migration. Pin 3.2.1 if you want a published artefact, and read CHANGELOG.md in the tree for the project's change history. The licence is BSD-3-Clause.
Two Composer commands decide whether it reaches production
Installation is the other thing the README covers, and it offers both variants of one command:
composer require phar-io/versioncomposer require --dev phar-io/versionThe first adds it as a local, per-project dependency. The second is for when you only need it during development, with running your project's test suite given as the example. That choice is not cosmetic: it decides whether the package is installed on a production machine, which matters more for a library that is often pulled in by tooling than for one that ships inside your application. Note what the page does not contain. There is no framework integration, no service provider, no configuration file, and no mention of PHP version requirements, so the version floor is something you will discover from Composer's own resolution rather than from this documentation. The development apparatus is in the tree: build.xml, phive.xml, psalm.xml and phpunit.xml, and .php_cs.dist for style.
Editorial conclusion
Adopt it when you need to assert a version range in PHP and want the semantics spelled out rather than guessed, especially if you are writing tooling that validates released artefacts. Do not adopt it expecting dependency resolution, because complies() answers a yes or no question and never picks a version for you. Before you use a constraint in anger, write the pair out longhand: if you meant to stay inside a minor version, write ~1.0.0 rather than ~1.0, because the short form silently becomes a major-version range.
Frequently asked questions
What does phar-io/version do?
It handles version information and constraints in PHP. A Version value follows the semantic versioning schema of <major>.<minor>.<patch>, and a constraint describes a range or a discrete version number, optionally with an operator. VersionConstraintParser parses a constraint string and complies() answers whether a given Version satisfies it. As of 2.0.0, pre-release labels are supported and taken into account when comparing versions.
What is the difference between ^1.0 and ~1.0 in phar-io/version?
With a patch level present they differ. The caret operator ^1.0 can be written as >=1.0.0 <2.0.0 and means every version within major version 1, while the tilde operator ~1.0.0 can be written as >=1.0.0 <1.1.0 and means every version within minor version 1.1. Without a patch level the tilde operator behaves like the caret, so ~1.0 is identical to ^1.0.
How do I install phar-io/version?
With Composer, as a local per-project dependency: composer require phar-io/version. If you only need it during development, for instance to run your project's test suite, add it as a development-time dependency with composer require --dev phar-io/version. The package is BSD-3-Clause licensed, and its newest release is 3.2.1 from 2022-02-21.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/phar-io-version)Star history chart for your README
[](https://hysenlabs.com/projects/phar-io-version)Was this useful?