From 1a8a6f0f186b980db46150c2db4cf894dddaa831 Mon Sep 17 00:00:00 2001
From: Chris Minett <1084019+chrisminett@users.noreply.github.com>
Date: Mon, 9 Feb 2026 16:01:47 +0000
Subject: [PATCH 1/3] Drop support for php80
---
.github/workflows/code-checks.yml | 3 ---
CHANGELOG.md | 3 +++
composer.json | 2 +-
src/Path.php | 28 +++++++++++-----------------
tests/PathTest.php | 4 +---
5 files changed, 16 insertions(+), 24 deletions(-)
diff --git a/.github/workflows/code-checks.yml b/.github/workflows/code-checks.yml
index 2ea1d6c..aa1dd34 100644
--- a/.github/workflows/code-checks.yml
+++ b/.github/workflows/code-checks.yml
@@ -12,9 +12,6 @@ jobs:
strategy:
matrix:
php:
- - '7.3'
- - '7.4'
- - '8.0'
- '8.1'
- '8.2'
- '8.3'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c945d12..a7ed87c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
+### Removed
+- Removed support for PHP versions <= v8.0 as they are no longer
+ [actively supported](https://php.net/supported-versions.php) by the PHP project.
## [2.1.0] - 2021-09-11
### Added
diff --git a/composer.json b/composer.json
index f00616a..ebd5951 100644
--- a/composer.json
+++ b/composer.json
@@ -17,7 +17,7 @@
}
},
"require": {
- "php": "^7.3 || ^8",
+ "php": "^8.1",
"ext-mbstring": "*"
},
"require-dev": {
diff --git a/src/Path.php b/src/Path.php
index f1b162b..9957bad 100644
--- a/src/Path.php
+++ b/src/Path.php
@@ -8,7 +8,7 @@
* @package Phlib\Path
* @license LGPL-3.0
*/
-class Path implements \ArrayAccess, \Countable, \IteratorAggregate
+class Path implements \ArrayAccess, \Countable, \IteratorAggregate, \Stringable
{
/**
* Constants for info keys, used for asking for info with the info method
@@ -25,19 +25,12 @@ class Path implements \ArrayAccess, \Countable, \IteratorAggregate
public const INFO_ALL = 15;
- /**
- * The separator to use for delimiting parts of the path
- *
- * @var string
- */
- private $directorySeparator;
-
/**
* The parts of the path
*
* @var string[]
*/
- private $parts;
+ private array $parts;
/**
* Array containing the info properties of the path
@@ -51,9 +44,8 @@ class Path implements \ArrayAccess, \Countable, \IteratorAggregate
* Mapping of info keys to the key names used in the output
*
* @see Path::info
- * @var array
*/
- private $infoKeys = [
+ private array $infoKeys = [
self::INFO_DIRNAME => 'dirname',
self::INFO_BASENAME => 'basename',
self::INFO_EXTENSION => 'extension',
@@ -131,11 +123,11 @@ private static function splitPath(string $path, string $directorySeparator): arr
return $out;
}
- public function __construct(array $parts, string $directorySeparator = DIRECTORY_SEPARATOR)
- {
+ public function __construct(
+ array $parts,
+ private readonly string $directorySeparator = DIRECTORY_SEPARATOR,
+ ) {
$parts = $this->trimEmptyParts($parts);
-
- $this->directorySeparator = $directorySeparator;
$this->parts = $parts;
}
@@ -188,6 +180,7 @@ public function toString(): string
* @see pathinfo
* @return array|string
*/
+ #[\ReturnTypeWillChange]
public function info(int $options = self::INFO_ALL)
{
$this->parseInfo();
@@ -247,7 +240,7 @@ private function parseInfo(): void
*/
private function escapeParts(array $parts): array
{
- return array_map(function ($name) {
+ return array_map(function (string $name): string {
return self::escapeName($name);
}, $parts);
}
@@ -266,7 +259,7 @@ private function trimEmptyParts(array $parts): array
return [];
}
- return array_filter($parts, function ($part, $index) use ($emptyLeading) {
+ return array_filter($parts, function ($part, $index) use ($emptyLeading): bool {
if ($index === 0) {
// never trim first element to keep leading separators (e.g. '/foo')
return true;
@@ -289,6 +282,7 @@ public function offsetExists($offset): bool
return array_key_exists($offset, $this->parts);
}
+ #[\ReturnTypeWillChange]
public function offsetGet($offset)
{
return $this->parts[$offset];
diff --git a/tests/PathTest.php b/tests/PathTest.php
index 1c36e65..15ec43a 100644
--- a/tests/PathTest.php
+++ b/tests/PathTest.php
@@ -71,7 +71,7 @@ public function testEscapingPathSeparators(): void
'boz/.woz',
];
- $parts = array_map(function ($part) {
+ $parts = array_map(function (string $part): string {
return Path::escapeName($part);
}, $parts);
@@ -209,7 +209,6 @@ public function testDirnamePath(): void
$phlibPath = Path::fromString($path);
$dirPath = $phlibPath->getDirnamePath();
- $this->assertInstanceOf('\Phlib\Path', $dirPath);
$this->assertEquals($dir, $dirPath->info(Path::INFO_BASENAME));
$this->assertEquals($root, $dirPath->info(Path::INFO_DIRNAME));
}
@@ -232,7 +231,6 @@ public function testTrimStart(): void
$trimmed = $phlibPath->trimStart();
- $this->assertInstanceOf('\Phlib\Path', $trimmed);
$this->assertEquals('root/dir/file', $trimmed->toString());
$this->assertEquals(3, $trimmed->count());
}
From 82f49bdc2ccd3abf9140e2b7adbd5aab1edd47e8 Mon Sep 17 00:00:00 2001
From: Chris Minett <1084019+chrisminett@users.noreply.github.com>
Date: Mon, 9 Feb 2026 16:03:05 +0000
Subject: [PATCH 2/3] Upgrade ECS
---
composer.json | 2 +-
ecs.php | 19 +++++++++++++++++++
src/Path.php | 4 ++--
tests/PathTest.php | 2 +-
4 files changed, 23 insertions(+), 4 deletions(-)
diff --git a/composer.json b/composer.json
index ebd5951..57f6439 100644
--- a/composer.json
+++ b/composer.json
@@ -22,7 +22,7 @@
},
"require-dev": {
"phpunit/phpunit": "^9",
- "symplify/easy-coding-standard": "^12"
+ "symplify/easy-coding-standard": "^13"
},
"autoload-dev": {
"psr-4": {
diff --git a/ecs.php b/ecs.php
index c705127..b415f07 100644
--- a/ecs.php
+++ b/ecs.php
@@ -1,5 +1,9 @@
'none',
],
+ )
+
+ /*
+ * Rule from PER Coding Style 2.6:
+ * "If the list is split across multiple lines, then the last item MUST have a trailing comma."
+ */
+ ->withConfiguredRule(
+ \PhpCsFixer\Fixer\ControlStructure\TrailingCommaInMultilineFixer::class,
+ [
+ 'elements' => [
+ \PhpCsFixer\Fixer\ControlStructure\TrailingCommaInMultilineFixer::ELEMENTS_ARGUMENTS,
+ \PhpCsFixer\Fixer\ControlStructure\TrailingCommaInMultilineFixer::ELEMENTS_ARRAYS,
+ \PhpCsFixer\Fixer\ControlStructure\TrailingCommaInMultilineFixer::ELEMENTS_PARAMETERS,
+ ],
+ ],
);
diff --git a/src/Path.php b/src/Path.php
index 9957bad..00eb8c0 100644
--- a/src/Path.php
+++ b/src/Path.php
@@ -64,7 +64,7 @@ public static function escapeName(string $name, string $directorySeparator = DIR
[
'\\' => '\\\\', // escape the escape character
$directorySeparator => "\\{$directorySeparator}", // escape the separator
- ]
+ ],
);
}
@@ -81,7 +81,7 @@ public static function unescapeName(string $name, string $directorySeparator = D
[
'\\\\' => '\\',
"\\{$directorySeparator}" => "{$directorySeparator}",
- ]
+ ],
);
}
diff --git a/tests/PathTest.php b/tests/PathTest.php
index 15ec43a..1a33e02 100644
--- a/tests/PathTest.php
+++ b/tests/PathTest.php
@@ -32,7 +32,7 @@ public function testMatchesPathInfo(string $path): void
$this->assertPathInfoEquals(
$phpPathInfo,
$phlibPathInfo,
- "Failed asserting path info matched for path '{$path}'"
+ "Failed asserting path info matched for path '{$path}'",
);
}
From 4c8a53a9dfba9182a087b29360917a15e7c3539f Mon Sep 17 00:00:00 2001
From: Chris Minett <1084019+chrisminett@users.noreply.github.com>
Date: Mon, 9 Feb 2026 16:06:39 +0000
Subject: [PATCH 3/3] Upgrade to PHPUnit v10
Conflicts:
tests/PathTest.php
---
.gitignore | 2 +-
.runConfigurations/All unit tests.run.xml | 2 +-
composer.json | 2 +-
phpunit.xml.dist | 7 +--
tests/PathTest.php | 63 +++++++++++------------
5 files changed, 37 insertions(+), 39 deletions(-)
diff --git a/.gitignore b/.gitignore
index 4901aab..532499f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,3 @@
+/.cache/*
/vendor
/composer.lock
-/.phpunit.result.cache
diff --git a/.runConfigurations/All unit tests.run.xml b/.runConfigurations/All unit tests.run.xml
index 0a179b1..1c5c127 100644
--- a/.runConfigurations/All unit tests.run.xml
+++ b/.runConfigurations/All unit tests.run.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/composer.json b/composer.json
index 57f6439..04b4e42 100644
--- a/composer.json
+++ b/composer.json
@@ -21,7 +21,7 @@
"ext-mbstring": "*"
},
"require-dev": {
- "phpunit/phpunit": "^9",
+ "phpunit/phpunit": "^10",
"symplify/easy-coding-standard": "^13"
},
"autoload-dev": {
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 6c17a6a..3701013 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -1,9 +1,10 @@
@@ -11,9 +12,9 @@
tests
-
+
src
-
+
diff --git a/tests/PathTest.php b/tests/PathTest.php
index 1a33e02..6658b41 100644
--- a/tests/PathTest.php
+++ b/tests/PathTest.php
@@ -4,6 +4,7 @@
namespace Phlib;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
/**
@@ -16,14 +17,12 @@ public function testCreateFromParts(): void
{
$parts = ['foo', 'bar/baz', 'taz'];
$phlibPath = new Path($parts);
- $this->assertEquals('foo/bar\\/baz/taz', $phlibPath->toString());
+ static::assertSame('foo/bar\\/baz/taz', $phlibPath->toString());
// Also test magic `__toString()`
- $this->assertEquals('foo/bar\\/baz/taz', (string)$phlibPath);
+ static::assertSame('foo/bar\\/baz/taz', (string)$phlibPath);
}
- /**
- * @dataProvider matchesPathInfoProvider
- */
+ #[DataProvider('matchesPathInfoProvider')]
public function testMatchesPathInfo(string $path): void
{
$phpPathInfo = pathinfo($path);
@@ -36,7 +35,7 @@ public function testMatchesPathInfo(string $path): void
);
}
- public function matchesPathInfoProvider(): array
+ public static function matchesPathInfoProvider(): array
{
return [
['foo'],
@@ -76,19 +75,17 @@ public function testEscapingPathSeparators(): void
}, $parts);
$phlibPath = Path::fromString(implode('/', $parts));
- $this->assertEquals(3, count($phlibPath));
+ static::assertSame(3, count($phlibPath));
}
- /**
- * @dataProvider ignoresEscapedSeparatorsProvider
- */
+ #[DataProvider('ignoresEscapedSeparatorsProvider')]
public function testIgnoresEscapedSeparators(string $path, int $expectedCount): void
{
$phlibPath = Path::fromString($path);
- $this->assertEquals($expectedCount, count($phlibPath), "Failed asserting path count for path '{$path}'");
+ static::assertSame($expectedCount, count($phlibPath), "Failed asserting path count for path '{$path}'");
}
- public function ignoresEscapedSeparatorsProvider(): array
+ public static function ignoresEscapedSeparatorsProvider(): array
{
return [
['foo\\/bar', 1],
@@ -105,10 +102,10 @@ public function testPathInfoOption(): void
{
$path = 'foo/bar/baz.taz';
$phlibPath = Path::fromString($path);
- $this->assertEquals(pathinfo($path, PATHINFO_BASENAME), $phlibPath->info(Path::INFO_BASENAME));
- $this->assertEquals(pathinfo($path, PATHINFO_DIRNAME), $phlibPath->info(Path::INFO_DIRNAME));
- $this->assertEquals(pathinfo($path, PATHINFO_FILENAME), $phlibPath->info(Path::INFO_FILENAME));
- $this->assertEquals(pathinfo($path, PATHINFO_EXTENSION), $phlibPath->info(Path::INFO_EXTENSION));
+ static::assertSame(pathinfo($path, PATHINFO_BASENAME), $phlibPath->info(Path::INFO_BASENAME));
+ static::assertSame(pathinfo($path, PATHINFO_DIRNAME), $phlibPath->info(Path::INFO_DIRNAME));
+ static::assertSame(pathinfo($path, PATHINFO_FILENAME), $phlibPath->info(Path::INFO_FILENAME));
+ static::assertSame(pathinfo($path, PATHINFO_EXTENSION), $phlibPath->info(Path::INFO_EXTENSION));
}
public function testPathInfoMultipleOptions(): void
@@ -136,21 +133,21 @@ public function testPathInfoMultipleOptionsNotAllPresent(): void
];
$actual = $phlibPath->info(Path::INFO_FILENAME | Path::INFO_EXTENSION);
- $this->assertIsArray($actual);
+ static::assertIsArray($actual);
$this->assertPathInfoEquals($expected, $actual);
}
public function testCountable(): void
{
$phlibPath = Path::fromString('foo/bar/baz.taz');
- $this->assertEquals(3, count($phlibPath));
+ static::assertSame(3, count($phlibPath));
}
public function testOffsetAccess(): void
{
$phlibPath = Path::fromString('foo/bar/baz.taz');
- $this->assertTrue(isset($phlibPath[1]));
- $this->assertEquals('baz.taz', $phlibPath[2]);
+ static::assertTrue(isset($phlibPath[1]));
+ static::assertSame('baz.taz', $phlibPath[2]);
}
public function testOffsetsAreImmutable(): void
@@ -176,7 +173,7 @@ public function testIterable(): void
foreach ($phlibPath as $part) {
$out[] = $part;
}
- $this->assertEquals('foo::bar::baz.taz', implode('::', $out));
+ static::assertSame('foo::bar::baz.taz', implode('::', $out));
}
public function testPartsAreUnescaped(): void
@@ -186,8 +183,8 @@ public function testPartsAreUnescaped(): void
$path = $dir . '/' . Path::escapeName($name);
$phlibPath = Path::fromString($path);
- $this->assertEquals($name, $phlibPath->info(Path::INFO_BASENAME));
- $this->assertEquals($name, $phlibPath[1]);
+ static::assertSame($name, $phlibPath->info(Path::INFO_BASENAME));
+ static::assertSame($name, $phlibPath[1]);
}
public function testToStringReEscapes(): void
@@ -197,7 +194,7 @@ public function testToStringReEscapes(): void
$path = $dir . '/' . Path::escapeName($name);
$phlibPath = Path::fromString($path);
- $this->assertEquals($path, $phlibPath->toString());
+ static::assertSame($path, $phlibPath->toString());
}
public function testDirnamePath(): void
@@ -209,8 +206,8 @@ public function testDirnamePath(): void
$phlibPath = Path::fromString($path);
$dirPath = $phlibPath->getDirnamePath();
- $this->assertEquals($dir, $dirPath->info(Path::INFO_BASENAME));
- $this->assertEquals($root, $dirPath->info(Path::INFO_DIRNAME));
+ static::assertSame($dir, $dirPath->info(Path::INFO_BASENAME));
+ static::assertSame($root, $dirPath->info(Path::INFO_DIRNAME));
}
public function testSlice(): void
@@ -218,10 +215,10 @@ public function testSlice(): void
$path = 'root/dir/file';
$phlibPath = Path::fromString($path);
- $this->assertEquals('dir/file', $phlibPath->slice(1)->toString());
- $this->assertEquals('root/dir', $phlibPath->slice(0, -1)->toString());
- $this->assertEquals('file', $phlibPath->slice(-1)->toString());
- $this->assertEquals('root', $phlibPath->slice(0, 1)->toString());
+ static::assertSame('dir/file', $phlibPath->slice(1)->toString());
+ static::assertSame('root/dir', $phlibPath->slice(0, -1)->toString());
+ static::assertSame('file', $phlibPath->slice(-1)->toString());
+ static::assertSame('root', $phlibPath->slice(0, 1)->toString());
}
public function testTrimStart(): void
@@ -231,8 +228,8 @@ public function testTrimStart(): void
$trimmed = $phlibPath->trimStart();
- $this->assertEquals('root/dir/file', $trimmed->toString());
- $this->assertEquals(3, $trimmed->count());
+ static::assertSame('root/dir/file', $trimmed->toString());
+ static::assertSame(3, $trimmed->count());
}
/**
@@ -242,6 +239,6 @@ private function assertPathInfoEquals(array $expected, array $actual, string $me
{
ksort($expected);
ksort($actual);
- $this->assertEquals($expected, $actual, $message);
+ static::assertSame($expected, $actual, $message);
}
}