New Upstream Release - php-vlucas-phpdotenv

Ready changes

Summary

Merged new upstream version: 5.5.0 (was: 5.4.1).

Resulting package

Built on 2022-12-31T05:08 (took 4m34s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases php-vlucas-phpdotenv

Lintian Result

Diff

diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..4c05913
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,17 @@
+* text=auto
+
+/tests export-ignore
+/.editorconfig export-ignore
+/.gitattributes export-ignore
+/.github export-ignore
+/.gitignore export-ignore
+/.github export-ignore
+/Makefile export-ignore
+/phpstan.src.neon.dist export-ignore
+/phpstan.tests.neon.dist export-ignore
+/phpunit.xml.dist export-ignore
+/psalm-baseline.xml export-ignore
+/psalm.xml export-ignore
+/README.md export-ignore
+/UPGRADING.md export-ignore
+/vendor-bin export-ignore
diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml
index 1f104e3..c650ce8 100644
--- a/.github/workflows/static.yml
+++ b/.github/workflows/static.yml
@@ -7,28 +7,28 @@ on:
 jobs:
   phpstan_src:
     name: PHPStan Source
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
 
     steps:
       - name: Checkout code
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
 
       - name: Setup PHP
         uses: shivammathur/setup-php@v2
         with:
-          php-version: 7.4
+          php-version: 8.2
           tools: composer:v2
           coverage: none
 
       - name: Install Dependencies
-        uses: nick-invision/retry@v1
+        uses: nick-invision/retry@v2
         with:
           timeout_minutes: 5
           max_attempts: 5
           command: composer update --no-interaction --no-progress
 
       - name: Install PHPStan
-        uses: nick-invision/retry@v1
+        uses: nick-invision/retry@v2
         with:
           timeout_minutes: 5
           max_attempts: 5
@@ -39,28 +39,28 @@ jobs:
 
   phpstan_tests:
     name: PHPStan Tests
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
 
     steps:
       - name: Checkout code
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
 
       - name: Setup PHP
         uses: shivammathur/setup-php@v2
         with:
-          php-version: 7.4
+          php-version: 8.2
           tools: composer:v2
           coverage: none
 
       - name: Install Dependencies
-        uses: nick-invision/retry@v1
+        uses: nick-invision/retry@v2
         with:
           timeout_minutes: 5
           max_attempts: 5
           command: composer update --no-interaction --no-progress
 
       - name: Install PHPStan
-        uses: nick-invision/retry@v1
+        uses: nick-invision/retry@v2
         with:
           timeout_minutes: 5
           max_attempts: 5
@@ -71,28 +71,28 @@ jobs:
 
   psalm:
     name: Psalm
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
 
     steps:
       - name: Checkout code
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
 
       - name: Setup PHP
         uses: shivammathur/setup-php@v2
         with:
-          php-version: 7.4
+          php-version: 8.2
           tools: composer:v2
           coverage: none
 
       - name: Install Dependencies
-        uses: nick-invision/retry@v1
+        uses: nick-invision/retry@v2
         with:
           timeout_minutes: 5
           max_attempts: 5
           command: composer update --no-interaction --no-progress
 
       - name: Install Psalm
-        uses: nick-invision/retry@v1
+        uses: nick-invision/retry@v2
         with:
           timeout_minutes: 5
           max_attempts: 5
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 44c4b42..0a42671 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -7,15 +7,15 @@ on:
 jobs:
   latest:
     name: PHP ${{ matrix.php }} Latest
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
 
     strategy:
       matrix:
-        php: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1']
+        php: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2']
 
     steps:
       - name: Checkout Code
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
 
       - name: Setup PHP
         uses: shivammathur/setup-php@v2
@@ -28,7 +28,7 @@ jobs:
         run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
 
       - name: Install Latest Dependencies
-        uses: nick-invision/retry@v1
+        uses: nick-invision/retry@v2
         with:
           timeout_minutes: 5
           max_attempts: 5
@@ -39,15 +39,15 @@ jobs:
 
   lowest:
     name: PHP ${{ matrix.php }} Lowest
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
 
     strategy:
       matrix:
-        php: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1']
+        php: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2']
 
     steps:
       - name: Checkout Code
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
 
       - name: Setup PHP
         uses: shivammathur/setup-php@v2
@@ -60,7 +60,7 @@ jobs:
         run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
 
       - name: Install Lowest Dependencies
-        uses: nick-invision/retry@v1
+        uses: nick-invision/retry@v2
         with:
           timeout_minutes: 5
           max_attempts: 5
diff --git a/Makefile b/Makefile
index ba109e9..4978c94 100644
--- a/Makefile
+++ b/Makefile
@@ -1,24 +1,24 @@
 install:
-	@docker run -it -w /data -v ${PWD}:/data:delegated -v ~/.composer:/root/.composer:delegated --entrypoint composer --rm registry.gitlab.com/grahamcampbell/php:7.4-base update
-	@docker run -it -w /data -v ${PWD}:/data:delegated -v ~/.composer:/root/.composer:delegated --entrypoint composer --rm registry.gitlab.com/grahamcampbell/php:7.4-base bin all update
+	@docker run -it -w /data -v ${PWD}:/data:delegated -v ~/.composer:/root/.composer:delegated --entrypoint composer --rm registry.gitlab.com/grahamcampbell/php:8.2-base update
+	@docker run -it -w /data -v ${PWD}:/data:delegated -v ~/.composer:/root/.composer:delegated --entrypoint composer --rm registry.gitlab.com/grahamcampbell/php:8.2-base bin all update
 
 phpunit:
-	@rm -f bootstrap/cache/*.php && docker run -it -w /data -v ${PWD}:/data:delegated --entrypoint vendor/bin/phpunit --rm registry.gitlab.com/grahamcampbell/php:7.4-cli
+	@docker run -it -w /data -v ${PWD}:/data:delegated --entrypoint vendor/bin/phpunit --rm registry.gitlab.com/grahamcampbell/php:8.2-cli
 
 phpstan-analyze-src:
-	@docker run -it -w /data -v ${PWD}:/data:delegated --entrypoint vendor/bin/phpstan --rm registry.gitlab.com/grahamcampbell/php:7.4-cli analyze src -c phpstan.src.neon.dist
+	@docker run -it -w /data -v ${PWD}:/data:delegated --entrypoint vendor/bin/phpstan --rm registry.gitlab.com/grahamcampbell/php:8.2-cli analyze src -c phpstan.src.neon.dist
 
 phpstan-analyze-tests:
-	@docker run -it -w /data -v ${PWD}:/data:delegated --entrypoint vendor/bin/phpstan --rm registry.gitlab.com/grahamcampbell/php:7.4-cli analyze tests -c phpstan.tests.neon.dist
+	@docker run -it -w /data -v ${PWD}:/data:delegated --entrypoint vendor/bin/phpstan --rm registry.gitlab.com/grahamcampbell/php:8.2-cli analyze tests -c phpstan.tests.neon.dist
 
 psalm-analyze:
-	@docker run -it -w /data -v ${PWD}:/data:delegated --entrypoint vendor/bin/psalm.phar --rm registry.gitlab.com/grahamcampbell/php:7.4-cli
+	@docker run -it -w /data -v ${PWD}:/data:delegated --entrypoint vendor/bin/psalm.phar --rm registry.gitlab.com/grahamcampbell/php:8.2-cli
 
 psalm-baseline:
 	@docker run -it -w /data -v ${PWD}:/data:delegated --entrypoint vendor/bin/psalm.phar --rm registry.gitlab.com/grahamcampbell/php:7.4-cli --set-baseline=psalm-baseline.xml
 
 psalm-show-info:
-	@docker run -it -w /data -v ${PWD}:/data:delegated --entrypoint vendor/bin/psalm.phar --rm registry.gitlab.com/grahamcampbell/php:7.4-cli --show-info=true
+	@docker run -it -w /data -v ${PWD}:/data:delegated --entrypoint vendor/bin/psalm.phar --rm registry.gitlab.com/grahamcampbell/php:8.2-cli --show-info=true
 
 test: phpunit phpstan-analyze-src phpstan-analyze-tests psalm-analyze
 
diff --git a/UPGRADING.md b/UPGRADING.md
index 7fd0a82..757f666 100644
--- a/UPGRADING.md
+++ b/UPGRADING.md
@@ -10,8 +10,8 @@ Release notes for 5.0.0 are available [here](https://github.com/vlucas/phpdotenv
 
 ### Details
 
-1. The `Dotenv\Dotenv::createImmutable` and `Dotenv\Dotenv::createMutable` methods no longer call will result in `getenv` and `putenv` being called. One should instead use `Dotenv\Dotenv::createUnsafeImmutable` and `Dotenv\Dotenv::createUnsafeMutable` methods if one really needs these functions.
-2. The `Dotenv\Dotenv` constructor has been modified to expect exactly 4 parameters: a store, a parser, a loader, and a repository. This likely only affect many people, since it is more common to construct this class via the public static create methods. Those methods have not changed.
+1. The `Dotenv\Dotenv::createImmutable` and `Dotenv\Dotenv::createMutable` methods no longer call will result in `getenv` and `putenv` being called. One should instead use `Dotenv\Dotenv::createUnsafeImmutable` and `Dotenv\Dotenv::createUnsafeMutable` methods, if one really needs these functions.
+2. The `Dotenv\Dotenv` constructor has been modified to expect exactly 4 parameters: a store, a parser, a loader, and a repository. This likely won't affect many people, since it is more common to construct this class via the public static create methods. Those methods have not changed.
 3. Scalar typehints have been added to the public interface.
 4. The parser now returns a result type instead of raising an exception. This change is strictly internal, and most users won't notice a difference. The responsibility for raising an exception has simply been shifted up to the caller.
 5. Adapters have been refactored again, with changes to the repositories. In particular, the repository builder has been tweaked. It now expects to be explicitly told if you want to use the default adapters or not, and expects individual readers and writers to be added, one by one. Similar changes have been applied to the store factory. Moreover, the `ApacheAdapter` has been changed so that it behaves much like the other adapters. The old behaviour can be simulated by composing it with the new `ReplacingWriter` (see below). We will no longer include this adapter in our default setup, so that people can enable exactly what they need. Finally, by default, we will no longer be using the `PutenvAdapter`. It can be added, as required.
@@ -78,18 +78,18 @@ Release notes for 4.0.0 are available [here](https://github.com/vlucas/phpdotenv
 
 ### Details
 
-V4 has again changed the way you initialize the `Dotenv` class. If you want immutable loading of environment variables, then replace `Dotenv::create` with `Dotenv::createImmutable`, and if you want mutable loading, replace `Dotenv::create` with `Dotenv::createMutable` and `->overload()` with `->load()`. The `overload` method has been removed in faviour of specifying mutability at object construction.
+V4 has again changed the way you initialize the `Dotenv` class. If you want immutable loading of environment variables, then replace `Dotenv::create` with `Dotenv::createImmutable`, and if you want mutable loading, replace `Dotenv::create` with `Dotenv::createMutable` and `->overload()` with `->load()`. The `overload` method has been removed in favour of specifying mutability at object construction.
 
-The behaviour when parsing single quoted strings has now changed, to mimic the behaviour of bash. It is no longer possible to escape characters in single quoted strings, and everything is treated literally. As soon as the first single quote character is read, after the initial one, then the variable is treated as ending immediately at that point. When parsing unquoted or double quoted strings, it is now possible to escape dollar signs, to forcefully avoid variable interpolation. Escaping dollars is not mandated, in the sense that if a dollar is present, and not following by variable interpolation sytnax, this is allowed, and the dollar will be treated as a literal dollar. Finally, interpolation of variables is now performed right to left, instead of left to right, so it is possible to nest interpolations to allow using the value of a variable as the name of another for further interpolation.
+The behaviour when parsing single quoted strings has now changed, to mimic the behaviour of bash. It is no longer possible to escape characters in single quoted strings, and everything is treated literally. As soon as the first single quote character is read, after the initial one, then the variable is treated as ending immediately at that point. When parsing unquoted or double quoted strings, it is now possible to escape dollar signs, to forcefully avoid variable interpolation. Escaping dollars is not mandated, in the sense that if a dollar is present, and not following by variable interpolation syntax, this is allowed, and the dollar will be treated as a literal dollar. Finally, interpolation of variables is now performed right to left, instead of left to right, so it is possible to nest interpolations to allow using the value of a variable as the name of another for further interpolation.
 
 The `getEnvironmentVariableNames` method is no longer available. This is because calls to `load()` (since v3.0.0) return an associative array of what was loaded, so `$dotenv->getEnvironmentVariableNames()` can be replaced with `array_keys($dotenv->load())`.
 
-There have been various internal refactorings. Appart from what has already been mentioned, the only other changes likely to affect developers is:
+There have been various internal refactorings. Apart from what has already been mentioned, the only other changes likely to affect developers is:
 
 1. The `Dotenv\Environment` namespace has been moved to `Dotenv\Repository`, the `Dotenv\Environment\Adapter\AdapterInterface` interface has been replaced by `Dotenv\Repository\Adapter\ReaderInterface` and `Dotenv\Repository\Adapter\WriterInterface`.
 2. The `Dotenv\Environment\DotenvFactory` has been (roughly) replaced by `Dotenv\Repository\RepositoryBuilder`, and `Dotenv\Environment\FactoryInterface` has been deleted.
 3. `Dotenv\Environment\AbstractVariables` has been replaced by `Dotenv\Repository\AbstractRepository`, `Dotenv\Environment\DotenvVariables` has been replaced by `Dotenv\Repository\AdapterRepository`, and `Dotenv\Environment\VariablesInterface` has been replaced by `Dotenv\Repository\RepositoryInterface`.
-4. The `Dotenv\Loader` class has been moved to `Dotenv\Loader\Loader`, and now has a different public interface. It no longer expects any parameters at construction, and implements only the new interface `Dotenv\Loader\LoaderInterface`. Its reponsibility has changed to purely taking raw env file content, and handing it off to the parser, dealing with variable interpolation, and sending off instructions to the repository to set variables. No longer can it be used as a way to read the environment by callers, and nor does it track immutability.
+4. The `Dotenv\Loader` class has been moved to `Dotenv\Loader\Loader`, and now has a different public interface. It no longer expects any parameters at construction, and implements only the new interface `Dotenv\Loader\LoaderInterface`. Its responsibility has changed to purely taking raw env file content, and handing it off to the parser, dealing with variable interpolation, and sending off instructions to the repository to set variables. No longer can it be used as a way to read the environment by callers, and nor does it track immutability.
 5. The `Dotenv\Parser` and `Dotenv\Lines` classes have moved to `Dotenv\Loader\Parser` and `Dotenv\Loader\Lines`, respectively. `Dotenv\Loader\Parser::parse` now return has either `null` or `Dotenv\Loader\Value` objects as values, instead of `string`s. This is to support the new variable interpolation and dollar escaping features.
 6. The `Dotenv\Validator` constructor has changed from `__construct(array $variables, Loader $loader, $required = true)` to `__construct(RepositoryInterface $repository, array $variables, $required = true)`.
 
@@ -136,7 +136,7 @@ $repository = RepositoryBuilder::create()
 $variables = (new Loader())->load($repository, $content);
 ```
 
-Notice, that compared to v3, the loader no longer expects file paths in the constructor. Reading of the files is now managed by the `Dotenv\Dotenv` class. The loader is geuinely just loading the content into the repository.
+Notice, that compared to v3, the loader no longer expects file paths in the constructor. Reading of the files is now managed by the `Dotenv\Dotenv` class. The loader is genuinely just loading the content into the repository.
 
 Finally, we note that the minimum supported version of PHP has increased to 5.5.9, up from 5.4.0 in V3 and 5.3.9 in V2.
 
diff --git a/composer.json b/composer.json
index 74800f8..46fdbaf 100644
--- a/composer.json
+++ b/composer.json
@@ -27,7 +27,7 @@
     "require-dev": {
         "ext-filter": "*",
         "bamarni/composer-bin-plugin": "^1.4.1",
-        "phpunit/phpunit": "^7.5.20 || ^8.5.21 || ^9.5.10"
+        "phpunit/phpunit": "^7.5.20 || ^8.5.30 || ^9.5.25"
     },
     "autoload": {
         "psr-4": {
@@ -43,11 +43,18 @@
         "ext-filter": "Required to use the boolean validator."
     },
     "config": {
+        "allow-plugins": {
+            "bamarni/composer-bin-plugin": true
+        },
         "preferred-install": "dist"
     },
     "extra": {
+        "bamarni-bin": {
+            "bin-links": true,
+            "forward-command": true
+        },
         "branch-alias": {
-            "dev-master": "5.4-dev"
+            "dev-master": "5.5-dev"
         }
     }
 }
diff --git a/debian/changelog b/debian/changelog
index b56cc0e..ec53c7f 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+php-vlucas-phpdotenv (5.5.0-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Sat, 31 Dec 2022 05:04:13 -0000
+
 php-vlucas-phpdotenv (5.4.1-1) unstable; urgency=medium
 
   [ Robin Gustafsson ]
diff --git a/phpstan.src.neon.dist b/phpstan.src.neon.dist
index 389d3a7..b4ac901 100644
--- a/phpstan.src.neon.dist
+++ b/phpstan.src.neon.dist
@@ -2,8 +2,6 @@ parameters:
   level: max
   ignoreErrors:
     - '#Only booleans are allowed in a negated boolean, int\|false given.#'
-    - '#Method Dotenv\\Util\\Regex::split\(\) should return GrahamCampbell\\ResultType\\Result\<array\<string\>, string\> but returns GrahamCampbell\\ResultType\\Result\<array\<int, bool\|string\>, string\>.#'
     - '#Anonymous function should return GrahamCampbell\\ResultType\\Result\<array\{mixed, mixed\}, string\> but returns GrahamCampbell\\ResultType\\Result\<array\{Dotenv\\Parser\\Value, mixed\}, string\>.#'
-    - '#Anonymous function should return GrahamCampbell\\ResultType\\Result\<non\-empty\-array, string\> but returns GrahamCampbell\\ResultType\\Result\<non\-empty\-array\<int, Dotenv\\Parser\\Entry\>, string\>.#'
     - '#Parameter \#1 \$readers of class Dotenv\\Repository\\RepositoryBuilder constructor expects array\<Dotenv\\Repository\\Adapter\\ReaderInterface\>, array\<Dotenv\\Repository\\Adapter\\ReaderInterface\|S\> given\.#'
     - '#Parameter \#2 \$writers of class Dotenv\\Repository\\RepositoryBuilder constructor expects array\<Dotenv\\Repository\\Adapter\\WriterInterface\>, array\<Dotenv\\Repository\\Adapter\\WriterInterface\|S\> given\.#'
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index 79057de..7270a15 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -1,10 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <files psalm-version="4.x-dev@">
-  <file src="src/Parser/EntryParser.php">
-    <InvalidArgument occurrences="1">
-      <code>flatMap</code>
-    </InvalidArgument>
-  </file>
   <file src="src/Repository/RepositoryBuilder.php">
     <InvalidStringClass occurrences="3">
       <code>$adapter::create()</code>
diff --git a/src/Parser/EntryParser.php b/src/Parser/EntryParser.php
index 5cfa3ee..e286840 100644
--- a/src/Parser/EntryParser.php
+++ b/src/Parser/EntryParser.php
@@ -74,6 +74,7 @@ final class EntryParser
         })->getOrElse([$line, null]);
 
         if ($result[0] === '') {
+            /** @var \GrahamCampbell\ResultType\Result<array{string,string|null},string> */
             return Error::create(self::getErrorMessage('an unexpected equals', $line));
         }
 
@@ -102,9 +103,11 @@ final class EntryParser
         }
 
         if (!self::isValidName($name)) {
+            /** @var \GrahamCampbell\ResultType\Result<string,string> */
             return Error::create(self::getErrorMessage('an invalid name', $name));
         }
 
+        /** @var \GrahamCampbell\ResultType\Result<string,string> */
         return Success::create($name);
     }
 
@@ -136,7 +139,7 @@ final class EntryParser
      */
     private static function isValidName(string $name)
     {
-        return Regex::matches('~\A[a-zA-Z0-9_.]+\z~', $name)->success()->getOrElse(false);
+        return Regex::matches('~(*UTF8)\A[\p{Ll}\p{Lu}\p{M}\p{N}_.]+\z~', $name)->success()->getOrElse(false);
     }
 
     /**
@@ -154,6 +157,7 @@ final class EntryParser
     private static function parseValue(string $value)
     {
         if (\trim($value) === '') {
+            /** @var \GrahamCampbell\ResultType\Result<\Dotenv\Parser\Value,string> */
             return Success::create(Value::blank());
         }
 
@@ -164,10 +168,13 @@ final class EntryParser
                 });
             });
         }, Success::create([Value::blank(), self::INITIAL_STATE]))->flatMap(static function (array $result) {
+            /** @psalm-suppress DocblockTypeContradiction */
             if (in_array($result[1], self::REJECT_STATES, true)) {
+                /** @var \GrahamCampbell\ResultType\Result<\Dotenv\Parser\Value,string> */
                 return Error::create('a missing closing quote');
             }
 
+            /** @var \GrahamCampbell\ResultType\Result<\Dotenv\Parser\Value,string> */
             return Success::create($result[0]);
         })->mapError(static function (string $err) use ($value) {
             return self::getErrorMessage($err, $value);
diff --git a/src/Parser/Lines.php b/src/Parser/Lines.php
index 3839794..6497993 100644
--- a/src/Parser/Lines.php
+++ b/src/Parser/Lines.php
@@ -58,15 +58,17 @@ final class Lines
      */
     private static function multilineProcess(bool $multiline, string $line, array $buffer)
     {
+        $startsOnCurrentLine = $multiline ? false : self::looksLikeMultilineStart($line);
+
         // check if $line can be multiline variable
-        if ($started = self::looksLikeMultilineStart($line)) {
+        if ($startsOnCurrentLine) {
             $multiline = true;
         }
 
         if ($multiline) {
             \array_push($buffer, $line);
 
-            if (self::looksLikeMultilineStop($line, $started)) {
+            if (self::looksLikeMultilineStop($line, $startsOnCurrentLine)) {
                 $multiline = false;
                 $line = \implode("\n", $buffer);
                 $buffer = [];
@@ -104,7 +106,7 @@ final class Lines
             return true;
         }
 
-        return Regex::occurences('/(?=([^\\\\]"))/', \str_replace('\\\\', '', $line))->map(static function (int $count) use ($started) {
+        return Regex::occurrences('/(?=([^\\\\]"))/', \str_replace('\\\\', '', $line))->map(static function (int $count) use ($started) {
             return $started ? $count > 1 : $count >= 1;
         })->success()->getOrElse(false);
     }
diff --git a/src/Parser/Parser.php b/src/Parser/Parser.php
index 3c115e5..2d30dfd 100644
--- a/src/Parser/Parser.php
+++ b/src/Parser/Parser.php
@@ -44,6 +44,7 @@ final class Parser implements ParserInterface
         return \array_reduce($entries, static function (Result $result, string $raw) {
             return $result->flatMap(static function (array $entries) use ($raw) {
                 return EntryParser::parse($raw)->map(static function (Entry $entry) use ($entries) {
+                    /** @var \Dotenv\Parser\Entry[] */
                     return \array_merge($entries, [$entry]);
                 });
             });
diff --git a/src/Repository/Adapter/ApacheAdapter.php b/src/Repository/Adapter/ApacheAdapter.php
index 868033a..af0aae1 100644
--- a/src/Repository/Adapter/ApacheAdapter.php
+++ b/src/Repository/Adapter/ApacheAdapter.php
@@ -50,7 +50,7 @@ final class ApacheAdapter implements AdapterInterface
     /**
      * Read an environment variable, if it exists.
      *
-     * @param string $name
+     * @param non-empty-string $name
      *
      * @return \PhpOption\Option<string>
      */
@@ -65,8 +65,8 @@ final class ApacheAdapter implements AdapterInterface
     /**
      * Write to an environment variable, if possible.
      *
-     * @param string $name
-     * @param string $value
+     * @param non-empty-string $name
+     * @param string           $value
      *
      * @return bool
      */
@@ -78,7 +78,7 @@ final class ApacheAdapter implements AdapterInterface
     /**
      * Delete an environment variable, if possible.
      *
-     * @param string $name
+     * @param non-empty-string $name
      *
      * @return bool
      */
diff --git a/src/Repository/Adapter/ArrayAdapter.php b/src/Repository/Adapter/ArrayAdapter.php
index 2881a7e..df64cf6 100644
--- a/src/Repository/Adapter/ArrayAdapter.php
+++ b/src/Repository/Adapter/ArrayAdapter.php
@@ -40,7 +40,7 @@ final class ArrayAdapter implements AdapterInterface
     /**
      * Read an environment variable, if it exists.
      *
-     * @param string $name
+     * @param non-empty-string $name
      *
      * @return \PhpOption\Option<string>
      */
@@ -52,8 +52,8 @@ final class ArrayAdapter implements AdapterInterface
     /**
      * Write to an environment variable, if possible.
      *
-     * @param string $name
-     * @param string $value
+     * @param non-empty-string $name
+     * @param string           $value
      *
      * @return bool
      */
@@ -67,7 +67,7 @@ final class ArrayAdapter implements AdapterInterface
     /**
      * Delete an environment variable, if possible.
      *
-     * @param string $name
+     * @param non-empty-string $name
      *
      * @return bool
      */
diff --git a/src/Repository/Adapter/EnvConstAdapter.php b/src/Repository/Adapter/EnvConstAdapter.php
index 9ef7fb4..9eb1947 100644
--- a/src/Repository/Adapter/EnvConstAdapter.php
+++ b/src/Repository/Adapter/EnvConstAdapter.php
@@ -33,7 +33,7 @@ final class EnvConstAdapter implements AdapterInterface
     /**
      * Read an environment variable, if it exists.
      *
-     * @param string $name
+     * @param non-empty-string $name
      *
      * @return \PhpOption\Option<string>
      */
@@ -41,6 +41,9 @@ final class EnvConstAdapter implements AdapterInterface
     {
         /** @var \PhpOption\Option<string> */
         return Option::fromArraysValue($_ENV, $name)
+            ->filter(static function ($value) {
+                return \is_scalar($value);
+            })
             ->map(static function ($value) {
                 if ($value === false) {
                     return 'false';
@@ -50,17 +53,16 @@ final class EnvConstAdapter implements AdapterInterface
                     return 'true';
                 }
 
-                return $value;
-            })->filter(static function ($value) {
-                return \is_string($value);
+                /** @psalm-suppress PossiblyInvalidCast */
+                return (string) $value;
             });
     }
 
     /**
      * Write to an environment variable, if possible.
      *
-     * @param string $name
-     * @param string $value
+     * @param non-empty-string $name
+     * @param string           $value
      *
      * @return bool
      */
@@ -74,7 +76,7 @@ final class EnvConstAdapter implements AdapterInterface
     /**
      * Delete an environment variable, if possible.
      *
-     * @param string $name
+     * @param non-empty-string $name
      *
      * @return bool
      */
diff --git a/src/Repository/Adapter/GuardedWriter.php b/src/Repository/Adapter/GuardedWriter.php
index 7bb69e8..fed8b9b 100644
--- a/src/Repository/Adapter/GuardedWriter.php
+++ b/src/Repository/Adapter/GuardedWriter.php
@@ -37,8 +37,8 @@ final class GuardedWriter implements WriterInterface
     /**
      * Write to an environment variable, if possible.
      *
-     * @param string $name
-     * @param string $value
+     * @param non-empty-string $name
+     * @param string           $value
      *
      * @return bool
      */
@@ -56,7 +56,7 @@ final class GuardedWriter implements WriterInterface
     /**
      * Delete an environment variable, if possible.
      *
-     * @param string $name
+     * @param non-empty-string $name
      *
      * @return bool
      */
@@ -74,7 +74,7 @@ final class GuardedWriter implements WriterInterface
     /**
      * Determine if the given variable is allowed.
      *
-     * @param string $name
+     * @param non-empty-string $name
      *
      * @return bool
      */
diff --git a/src/Repository/Adapter/ImmutableWriter.php b/src/Repository/Adapter/ImmutableWriter.php
index 574fcd6..399e6f9 100644
--- a/src/Repository/Adapter/ImmutableWriter.php
+++ b/src/Repository/Adapter/ImmutableWriter.php
@@ -45,8 +45,8 @@ final class ImmutableWriter implements WriterInterface
     /**
      * Write to an environment variable, if possible.
      *
-     * @param string $name
-     * @param string $value
+     * @param non-empty-string $name
+     * @param string           $value
      *
      * @return bool
      */
@@ -72,7 +72,7 @@ final class ImmutableWriter implements WriterInterface
     /**
      * Delete an environment variable, if possible.
      *
-     * @param string $name
+     * @param non-empty-string $name
      *
      * @return bool
      */
@@ -99,7 +99,7 @@ final class ImmutableWriter implements WriterInterface
      *
      * That is, is it an "existing" variable.
      *
-     * @param string $name
+     * @param non-empty-string $name
      *
      * @return bool
      */
diff --git a/src/Repository/Adapter/MultiReader.php b/src/Repository/Adapter/MultiReader.php
index 12b3bda..0cfda6f 100644
--- a/src/Repository/Adapter/MultiReader.php
+++ b/src/Repository/Adapter/MultiReader.php
@@ -30,7 +30,7 @@ final class MultiReader implements ReaderInterface
     /**
      * Read an environment variable, if it exists.
      *
-     * @param string $name
+     * @param non-empty-string $name
      *
      * @return \PhpOption\Option<string>
      */
diff --git a/src/Repository/Adapter/MultiWriter.php b/src/Repository/Adapter/MultiWriter.php
index e1dcf56..15a9d8f 100644
--- a/src/Repository/Adapter/MultiWriter.php
+++ b/src/Repository/Adapter/MultiWriter.php
@@ -28,8 +28,8 @@ final class MultiWriter implements WriterInterface
     /**
      * Write to an environment variable, if possible.
      *
-     * @param string $name
-     * @param string $value
+     * @param non-empty-string $name
+     * @param string           $value
      *
      * @return bool
      */
@@ -47,7 +47,7 @@ final class MultiWriter implements WriterInterface
     /**
      * Delete an environment variable, if possible.
      *
-     * @param string $name
+     * @param non-empty-string $name
      *
      * @return bool
      */
diff --git a/src/Repository/Adapter/PutenvAdapter.php b/src/Repository/Adapter/PutenvAdapter.php
index 126c465..6d017cd 100644
--- a/src/Repository/Adapter/PutenvAdapter.php
+++ b/src/Repository/Adapter/PutenvAdapter.php
@@ -48,7 +48,7 @@ final class PutenvAdapter implements AdapterInterface
     /**
      * Read an environment variable, if it exists.
      *
-     * @param string $name
+     * @param non-empty-string $name
      *
      * @return \PhpOption\Option<string>
      */
@@ -63,8 +63,8 @@ final class PutenvAdapter implements AdapterInterface
     /**
      * Write to an environment variable, if possible.
      *
-     * @param string $name
-     * @param string $value
+     * @param non-empty-string $name
+     * @param string           $value
      *
      * @return bool
      */
@@ -78,7 +78,7 @@ final class PutenvAdapter implements AdapterInterface
     /**
      * Delete an environment variable, if possible.
      *
-     * @param string $name
+     * @param non-empty-string $name
      *
      * @return bool
      */
diff --git a/src/Repository/Adapter/ReaderInterface.php b/src/Repository/Adapter/ReaderInterface.php
index 5ece5ee..306a63f 100644
--- a/src/Repository/Adapter/ReaderInterface.php
+++ b/src/Repository/Adapter/ReaderInterface.php
@@ -9,7 +9,7 @@ interface ReaderInterface
     /**
      * Read an environment variable, if it exists.
      *
-     * @param string $name
+     * @param non-empty-string $name
      *
      * @return \PhpOption\Option<string>
      */
diff --git a/src/Repository/Adapter/ReplacingWriter.php b/src/Repository/Adapter/ReplacingWriter.php
index 326cd18..98c0f04 100644
--- a/src/Repository/Adapter/ReplacingWriter.php
+++ b/src/Repository/Adapter/ReplacingWriter.php
@@ -45,8 +45,8 @@ final class ReplacingWriter implements WriterInterface
     /**
      * Write to an environment variable, if possible.
      *
-     * @param string $name
-     * @param string $value
+     * @param non-empty-string $name
+     * @param string           $value
      *
      * @return bool
      */
@@ -63,7 +63,7 @@ final class ReplacingWriter implements WriterInterface
     /**
      * Delete an environment variable, if possible.
      *
-     * @param string $name
+     * @param non-empty-string $name
      *
      * @return bool
      */
@@ -83,7 +83,7 @@ final class ReplacingWriter implements WriterInterface
      * Returns true if it currently exists, or existed at any point in the past
      * that we are aware of.
      *
-     * @param string $name
+     * @param non-empty-string $name
      *
      * @return bool
      */
diff --git a/src/Repository/Adapter/ServerConstAdapter.php b/src/Repository/Adapter/ServerConstAdapter.php
index 8e3dc98..f93b6e5 100644
--- a/src/Repository/Adapter/ServerConstAdapter.php
+++ b/src/Repository/Adapter/ServerConstAdapter.php
@@ -33,7 +33,7 @@ final class ServerConstAdapter implements AdapterInterface
     /**
      * Read an environment variable, if it exists.
      *
-     * @param string $name
+     * @param non-empty-string $name
      *
      * @return \PhpOption\Option<string>
      */
@@ -41,6 +41,9 @@ final class ServerConstAdapter implements AdapterInterface
     {
         /** @var \PhpOption\Option<string> */
         return Option::fromArraysValue($_SERVER, $name)
+            ->filter(static function ($value) {
+                return \is_scalar($value);
+            })
             ->map(static function ($value) {
                 if ($value === false) {
                     return 'false';
@@ -50,17 +53,16 @@ final class ServerConstAdapter implements AdapterInterface
                     return 'true';
                 }
 
-                return $value;
-            })->filter(static function ($value) {
-                return \is_string($value);
+                /** @psalm-suppress PossiblyInvalidCast */
+                return (string) $value;
             });
     }
 
     /**
      * Write to an environment variable, if possible.
      *
-     * @param string $name
-     * @param string $value
+     * @param non-empty-string $name
+     * @param string           $value
      *
      * @return bool
      */
@@ -74,7 +76,7 @@ final class ServerConstAdapter implements AdapterInterface
     /**
      * Delete an environment variable, if possible.
      *
-     * @param string $name
+     * @param non-empty-string $name
      *
      * @return bool
      */
diff --git a/src/Repository/Adapter/WriterInterface.php b/src/Repository/Adapter/WriterInterface.php
index 8b3fa57..4cb3d61 100644
--- a/src/Repository/Adapter/WriterInterface.php
+++ b/src/Repository/Adapter/WriterInterface.php
@@ -9,8 +9,8 @@ interface WriterInterface
     /**
      * Write to an environment variable, if possible.
      *
-     * @param string $name
-     * @param string $value
+     * @param non-empty-string $name
+     * @param string           $value
      *
      * @return bool
      */
@@ -19,7 +19,7 @@ interface WriterInterface
     /**
      * Delete an environment variable, if possible.
      *
-     * @param string $name
+     * @param non-empty-string $name
      *
      * @return bool
      */
diff --git a/src/Repository/AdapterRepository.php b/src/Repository/AdapterRepository.php
index ada1c45..e4b8fb7 100644
--- a/src/Repository/AdapterRepository.php
+++ b/src/Repository/AdapterRepository.php
@@ -6,6 +6,7 @@ namespace Dotenv\Repository;
 
 use Dotenv\Repository\Adapter\ReaderInterface;
 use Dotenv\Repository\Adapter\WriterInterface;
+use InvalidArgumentException;
 
 final class AdapterRepository implements RepositoryInterface
 {
@@ -46,7 +47,7 @@ final class AdapterRepository implements RepositoryInterface
      */
     public function has(string $name)
     {
-        return $this->reader->read($name)->isDefined();
+        return '' !== $name && $this->reader->read($name)->isDefined();
     }
 
     /**
@@ -54,10 +55,16 @@ final class AdapterRepository implements RepositoryInterface
      *
      * @param string $name
      *
+     * @throws \InvalidArgumentException
+     *
      * @return string|null
      */
     public function get(string $name)
     {
+        if ('' === $name) {
+            throw new InvalidArgumentException('Expected name to be a non-empty string.');
+        }
+
         return $this->reader->read($name)->getOrElse(null);
     }
 
@@ -67,10 +74,16 @@ final class AdapterRepository implements RepositoryInterface
      * @param string $name
      * @param string $value
      *
+     * @throws \InvalidArgumentException
+     *
      * @return bool
      */
     public function set(string $name, string $value)
     {
+        if ('' === $name) {
+            throw new InvalidArgumentException('Expected name to be a non-empty string.');
+        }
+
         return $this->writer->write($name, $value);
     }
 
@@ -79,10 +92,16 @@ final class AdapterRepository implements RepositoryInterface
      *
      * @param string $name
      *
+     * @throws \InvalidArgumentException
+     *
      * @return bool
      */
     public function clear(string $name)
     {
+        if ('' === $name) {
+            throw new InvalidArgumentException('Expected name to be a non-empty string.');
+        }
+
         return $this->writer->delete($name);
     }
 }
diff --git a/src/Repository/RepositoryBuilder.php b/src/Repository/RepositoryBuilder.php
index 92f65e9..a042f9a 100644
--- a/src/Repository/RepositoryBuilder.php
+++ b/src/Repository/RepositoryBuilder.php
@@ -111,7 +111,7 @@ final class RepositoryBuilder
     }
 
     /**
-     * Determine if the given name if of an adapaterclass.
+     * Determine if the given name if of an adapterclass.
      *
      * @param string $name
      *
diff --git a/src/Repository/RepositoryInterface.php b/src/Repository/RepositoryInterface.php
index a2a7d32..d9b18a4 100644
--- a/src/Repository/RepositoryInterface.php
+++ b/src/Repository/RepositoryInterface.php
@@ -20,6 +20,8 @@ interface RepositoryInterface
      *
      * @param string $name
      *
+     * @throws \InvalidArgumentException
+     *
      * @return string|null
      */
     public function get(string $name);
@@ -30,6 +32,8 @@ interface RepositoryInterface
      * @param string $name
      * @param string $value
      *
+     * @throws \InvalidArgumentException
+     *
      * @return bool
      */
     public function set(string $name, string $value);
@@ -39,6 +43,8 @@ interface RepositoryInterface
      *
      * @param string $name
      *
+     * @throws \InvalidArgumentException
+     *
      * @return bool
      */
     public function clear(string $name);
diff --git a/src/Util/Regex.php b/src/Util/Regex.php
index e558f40..52c1578 100644
--- a/src/Util/Regex.php
+++ b/src/Util/Regex.php
@@ -47,7 +47,7 @@ final class Regex
      *
      * @return \GrahamCampbell\ResultType\Result<int,string>
      */
-    public static function occurences(string $pattern, string $subject)
+    public static function occurrences(string $pattern, string $subject)
     {
         return self::pregAndWrap(static function (string $subject) use ($pattern) {
             return (int) @\preg_match_all($pattern, $subject);
@@ -102,9 +102,11 @@ final class Regex
         $result = $operation($subject);
 
         if (\preg_last_error() !== \PREG_NO_ERROR) {
+            /** @var \GrahamCampbell\ResultType\Result<V,string> */
             return Error::create(\preg_last_error_msg());
         }
 
+        /** @var \GrahamCampbell\ResultType\Result<V,string> */
         return Success::create($result);
     }
 }
diff --git a/tests/Dotenv/DotenvTest.php b/tests/Dotenv/DotenvTest.php
index dc77853..97ddfd7 100644
--- a/tests/Dotenv/DotenvTest.php
+++ b/tests/Dotenv/DotenvTest.php
@@ -317,7 +317,7 @@ final class DotenvTest extends TestCase
         self::assertSame('secret!@#', \getenv('SPVAR8'));
     }
 
-    public function testMutlilineLoading()
+    public function testMultilineLoading()
     {
         $dotenv = Dotenv::createUnsafeMutable(self::$folder, 'multiline.env');
         $dotenv->load();
@@ -335,6 +335,14 @@ final class DotenvTest extends TestCase
         self::assertSame(['EMPTY_VAR' => null], $dotenv->load());
     }
 
+    public function testUnicodeVarNames()
+    {
+        $dotenv = Dotenv::createImmutable(self::$folder, 'unicodevarnames.env');
+        $dotenv->load();
+        self::assertSame('Skybert', $_SERVER['AlbertÅberg']);
+        self::assertSame('2022-04-01T00:00', $_SERVER['ДатаЗакрытияРасчетногоПериода']);
+    }
+
     public function testDirectConstructor()
     {
         $repository = RepositoryBuilder::createWithDefaultAdapters()->make();
diff --git a/tests/Dotenv/Parser/EntryParserTest.php b/tests/Dotenv/Parser/EntryParserTest.php
index e61be25..8a5f5f6 100644
--- a/tests/Dotenv/Parser/EntryParserTest.php
+++ b/tests/Dotenv/Parser/EntryParserTest.php
@@ -24,6 +24,12 @@ final class EntryParserTest extends TestCase
         $this->checkEmptyResult($result, 'FOO');
     }
 
+    public function testUnicodeNameParse()
+    {
+        $result = EntryParser::parse('FOOƱ=BAZ');
+        $this->checkPositiveResult($result, 'FOOƱ', 'BAZ');
+    }
+
     public function testQuotesParse()
     {
         $result = EntryParser::parse("FOO=\"BAR  \n\"");
@@ -139,12 +145,6 @@ final class EntryParserTest extends TestCase
         $this->checkErrorResult($result, 'Encountered an invalid name at [FOO_ASD!].');
     }
 
-    public function testParseUnicodeName()
-    {
-        $result = EntryParser::parse('FOOƱ=BAZ');
-        $this->checkErrorResult($result, 'Encountered an invalid name at [FOOƱ].');
-    }
-
     public function testParserEscapingDouble()
     {
         $result = EntryParser::parse('FOO_BAD="iiiiviiiixiiiiviiii\\a"');
diff --git a/tests/Dotenv/Parser/LinesTest.php b/tests/Dotenv/Parser/LinesTest.php
index 3f0502f..261029a 100644
--- a/tests/Dotenv/Parser/LinesTest.php
+++ b/tests/Dotenv/Parser/LinesTest.php
@@ -45,34 +45,9 @@ final class LinesTest extends TestCase
             'TEST_NS=\'test\\ntest\'',
             'TEST_EQD="https://vision.googleapis.com/v1/images:annotate?key="',
             'TEST_EQS=\'https://vision.googleapis.com/v1/images:annotate?key=\'',
+            "BASE64_ENCODED_MULTILINE=\"qS1zCzMVVUJWQShokv6YVYi+ruKSC/bHV7GmEiyVkLaBWJHNVHCHsgTksEBsy8wJ\nuwycAvR07ZyOJJed4XTRMKnKp1/v+6UATpWzkIjZXytK+pD+XlZimUHTx3uiDcmU\njhQX1wWSxHDqrSWxeIJiTD+BuUyId8FzmXQ3TcBydJ474tmOU2F492ubk3LAiZ18\nmhiRGoshXAOSbS/P3+RZi4bDeNE/No4=\"",
         ];
 
         self::assertSame($expected, Lines::process($result->success()->get()));
     }
-
-    public function testProcessClosingSlash()
-    {
-        $lines = [
-            'SPVAR5="test some escaped characters like a quote \" or maybe a backslash \\" # not escaped',
-        ];
-
-        $expected = [
-            'SPVAR5="test some escaped characters like a quote \" or maybe a backslash \\" # not escaped',
-        ];
-
-        self::assertSame($expected, $lines);
-    }
-
-    public function testProcessBadQuotes()
-    {
-        $lines = [
-            "TEST=\"erert\nTEST='erert\n",
-        ];
-
-        $expected = [
-            "TEST=\"erert\nTEST='erert\n",
-        ];
-
-        self::assertSame($expected, $lines);
-    }
 }
diff --git a/tests/Dotenv/Repository/Adapter/EnvConstAdapterTest.php b/tests/Dotenv/Repository/Adapter/EnvConstAdapterTest.php
index 592f304..8e10b71 100644
--- a/tests/Dotenv/Repository/Adapter/EnvConstAdapterTest.php
+++ b/tests/Dotenv/Repository/Adapter/EnvConstAdapterTest.php
@@ -35,7 +35,7 @@ final class EnvConstAdapterTest extends TestCase
 
     public function testBadTypeRead()
     {
-        $_ENV['CONST_TEST'] = 123;
+        $_ENV['CONST_TEST'] = [123];
         $value = self::createAdapter()->read('CONST_TEST');
         self::assertFalse($value->isDefined());
     }
diff --git a/tests/Dotenv/Repository/Adapter/ServerConstAdapterTest.php b/tests/Dotenv/Repository/Adapter/ServerConstAdapterTest.php
index 7366b79..d322f77 100644
--- a/tests/Dotenv/Repository/Adapter/ServerConstAdapterTest.php
+++ b/tests/Dotenv/Repository/Adapter/ServerConstAdapterTest.php
@@ -35,7 +35,7 @@ final class ServerConstAdapterTest extends TestCase
 
     public function testBadTypeRead()
     {
-        $_SERVER['CONST_TEST'] = 123;
+        $_SERVER['CONST_TEST'] = [123];
         $value = self::createAdapter()->read('CONST_TEST');
         self::assertFalse($value->isDefined());
     }
diff --git a/tests/Dotenv/Repository/RepositoryTest.php b/tests/Dotenv/Repository/RepositoryTest.php
index 8f36f88..ce296dc 100644
--- a/tests/Dotenv/Repository/RepositoryTest.php
+++ b/tests/Dotenv/Repository/RepositoryTest.php
@@ -165,7 +165,7 @@ final class RepositoryTest extends TestCase
         self::assertSame('bar', $repo->get('FOO'));
     }
 
-    public function testGettingBadVariable()
+    public function testGettingNullVariable()
     {
         $repo = RepositoryBuilder::createWithDefaultAdapters()->make();
 
@@ -174,6 +174,16 @@ final class RepositoryTest extends TestCase
         $repo->get(null);
     }
 
+    public function testGettingEmptyVariable()
+    {
+        $repo = RepositoryBuilder::createWithDefaultAdapters()->make();
+
+        $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('Expected name to be a non-empty string.');
+
+        $repo->get('');
+    }
+
     public function testSettingVariable()
     {
         $this->load();
@@ -185,7 +195,7 @@ final class RepositoryTest extends TestCase
         self::assertSame('new', $repo->get('FOO'));
     }
 
-    public function testSettingBadVariable()
+    public function testSettingNullVariable()
     {
         $repo = RepositoryBuilder::createWithDefaultAdapters()->make();
 
@@ -194,6 +204,16 @@ final class RepositoryTest extends TestCase
         $repo->set(null, 'foo');
     }
 
+    public function testSettingEmptyVariable()
+    {
+        $repo = RepositoryBuilder::createWithDefaultAdapters()->make();
+
+        $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('Expected name to be a non-empty string.');
+
+        $repo->set('', 'foo');
+    }
+
     public function testClearingVariable()
     {
         $this->load();
@@ -217,7 +237,7 @@ final class RepositoryTest extends TestCase
         self::assertFalse($repo->has('FOO'));
     }
 
-    public function testClearingBadVariable()
+    public function testClearingNullVariable()
     {
         $repo = RepositoryBuilder::createWithDefaultAdapters()->make();
 
@@ -226,6 +246,16 @@ final class RepositoryTest extends TestCase
         $repo->clear(null);
     }
 
+    public function testClearingEmptyVariable()
+    {
+        $repo = RepositoryBuilder::createWithDefaultAdapters()->make();
+
+        $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('Expected name to be a non-empty string.');
+
+        $repo->clear('');
+    }
+
     public function testCannotSetVariableOnImmutableInstance()
     {
         $this->load();
diff --git a/tests/fixtures/env/multiline.env b/tests/fixtures/env/multiline.env
index 5ea54b0..ae1db4b 100644
--- a/tests/fixtures/env/multiline.env
+++ b/tests/fixtures/env/multiline.env
@@ -7,3 +7,8 @@ TEST_NS='test\ntest'
 
 TEST_EQD="https://vision.googleapis.com/v1/images:annotate?key="
 TEST_EQS='https://vision.googleapis.com/v1/images:annotate?key='
+
+BASE64_ENCODED_MULTILINE="qS1zCzMVVUJWQShokv6YVYi+ruKSC/bHV7GmEiyVkLaBWJHNVHCHsgTksEBsy8wJ
+uwycAvR07ZyOJJed4XTRMKnKp1/v+6UATpWzkIjZXytK+pD+XlZimUHTx3uiDcmU
+jhQX1wWSxHDqrSWxeIJiTD+BuUyId8FzmXQ3TcBydJ474tmOU2F492ubk3LAiZ18
+mhiRGoshXAOSbS/P3+RZi4bDeNE/No4="
diff --git a/tests/fixtures/env/unicodevarnames.env b/tests/fixtures/env/unicodevarnames.env
new file mode 100644
index 0000000..e86f24e
--- /dev/null
+++ b/tests/fixtures/env/unicodevarnames.env
@@ -0,0 +1,2 @@
+AlbertÅberg=Skybert
+ДатаЗакрытияРасчетногоПериода='2022-04-01T00:00'
diff --git a/vendor-bin/phpstan/composer.json b/vendor-bin/phpstan/composer.json
index 684fac8..ab97b1f 100644
--- a/vendor-bin/phpstan/composer.json
+++ b/vendor-bin/phpstan/composer.json
@@ -1,14 +1,17 @@
 {
     "require": {
-        "php": "^7.4",
-        "phpstan/phpstan": "1.2.0",
+        "php": "^8.2",
+        "phpstan/phpstan": "1.8.9",
         "phpstan/extension-installer": "1.1.0",
         "phpstan/phpstan-deprecation-rules": "1.0.0",
-        "phpstan/phpstan-phpunit": "1.0.0",
-        "phpstan/phpstan-strict-rules": "1.1.0",
+        "phpstan/phpstan-phpunit": "1.1.1",
+        "phpstan/phpstan-strict-rules": "1.4.4",
         "thecodingmachine/phpstan-strict-rules": "1.0.0"
     },
     "config": {
-        "preferred-install": "dist"
+        "preferred-install": "dist",
+        "allow-plugins": {
+            "phpstan/extension-installer": true
+        }
     }
 }
diff --git a/vendor-bin/psalm/composer.json b/vendor-bin/psalm/composer.json
index 5535542..24ea34a 100644
--- a/vendor-bin/psalm/composer.json
+++ b/vendor-bin/psalm/composer.json
@@ -1,7 +1,7 @@
 {
     "require": {
-        "php": "^7.4",
-        "psalm/phar": "4.15.0"
+        "php": "^8.2",
+        "psalm/phar": "4.29.0"
     },
     "config": {
         "preferred-install": "dist"

Debdiff

File lists identical (after any substitutions)

No differences were encountered in the control files

More details

Full run details