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); } }