diff --git a/.github/workflows/test-suite.yaml b/.github/workflows/test-suite.yaml
index a3abc65..ca77cc5 100644
--- a/.github/workflows/test-suite.yaml
+++ b/.github/workflows/test-suite.yaml
@@ -28,7 +28,7 @@ jobs:
run: composer update
- name: Run Static Analysis
- run: vendor/bin/psalm
+ run: vendor/bin/phpstan
tests:
name: Tests
diff --git a/Makefile b/Makefile
index 7f91e4f..baeb3c2 100644
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@ prod production: # Build application for production
test: # Run coding standards/static analysis checks and tests
@vendor/bin/php-cs-fixer fix --diff --dry-run \
- && vendor/bin/psalm \
+ && vendor/bin/phpstan \
&& vendor/bin/phpunit --coverage-text
coverage: # Generate an HTML coverage report
diff --git a/composer.json b/composer.json
index 394be37..67492ba 100644
--- a/composer.json
+++ b/composer.json
@@ -19,14 +19,14 @@
}
],
"require": {
- "php": ">=8.1",
- "symfony/yaml": "^6.0",
+ "php": "^8.0 || ^8.1 || ^8.2",
+ "symfony/yaml": "^5.0 || ^6.0",
"yosymfony/toml": "^1.0"
},
"require-dev": {
- "phlak/coding-standards": "^2.0",
+ "phlak/coding-standards": "^2.2",
+ "phpstan/phpstan": "^1.10",
"psy/psysh": "^0.11",
- "vimeo/psalm": "^5.15",
"yoast/phpunit-polyfills": "^2.0"
},
"autoload": {
diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
new file mode 100644
index 0000000..c908ca4
--- /dev/null
+++ b/phpstan-baseline.neon
@@ -0,0 +1,6 @@
+parameters:
+ ignoreErrors:
+ -
+ message: "#^Method PHLAK\\\\Config\\\\Config\\:\\:load\\(\\) throws checked exception PHLAK\\\\Config\\\\Exceptions\\\\InvalidFileException but it's missing from the PHPDoc @throws tag\\.$#"
+ count: 2
+ path: src/Config.php
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
new file mode 100644
index 0000000..f6b0a56
--- /dev/null
+++ b/phpstan.neon.dist
@@ -0,0 +1,27 @@
+parameters:
+
+ paths:
+ - src
+ - tests
+
+ level: max
+
+ checkFunctionNameCase: true
+ checkMissingIterableValueType: false
+
+ reportUnmatchedIgnoredErrors: false
+
+ exceptions:
+ implicitThrows: false
+
+ check:
+ missingCheckedExceptionInThrows: true
+ tooWideThrowType: true
+
+ uncheckedExceptionClasses:
+ - 'InvalidArgumentException'
+ - 'RuntimeException'
+ - 'PHPUnit\Framework\Exception'
+
+includes:
+ - phpstan-baseline.neon
diff --git a/psalm.xml b/psalm.xml
deleted file mode 100644
index 5bfb8e3..0000000
--- a/psalm.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Config.php b/src/Config.php
index 0933772..44c92c0 100644
--- a/src/Config.php
+++ b/src/Config.php
@@ -5,12 +5,16 @@
use ArrayAccess;
use DirectoryIterator;
use IteratorAggregate;
-use PHLAK\Config\Exceptions\InvalidContextException;
use PHLAK\Config\Interfaces\ConfigInterface;
+use PHLAK\Config\Loaders\Loader;
use PHLAK\Config\Traits\Arrayable;
use RuntimeException;
use SplFileInfo;
+/**
+ * @implements ArrayAccess
+ * @implements IteratorAggregate
+ */
class Config implements ConfigInterface, ArrayAccess, IteratorAggregate
{
use Arrayable;
@@ -21,28 +25,17 @@ class Config implements ConfigInterface, ArrayAccess, IteratorAggregate
/**
* Create a new Config object.
*
- * @param mixed $context Raw array of configuration options or path to a
- * configuration file or directory containing one or
- * more configuration files
- * @param string|array $prefix A key under which the loaded config will be nested
- * @throws InvalidContextException
+ * @param array|string $context Raw array of configuration options or path to a configuration file
+ * or directory containing one or more configuration files
+ * @param string $prefix A key under which the loaded config will be nested
*/
- public function __construct($context = null, string $prefix = null)
+ public function __construct(array|string $context = null, string $prefix = null)
{
- switch (gettype($context)) {
- case 'NULL':
- break;
- case 'array':
- $this->config = $prefix ? [$prefix => $context] : $context;
-
- break;
- case 'string':
- $this->load($context, $prefix);
-
- break;
- default:
- throw new InvalidContextException('Failed to initialize config');
- }
+ match (gettype($context)) {
+ 'array' => $this->config = $prefix ? [$prefix => $context] : $context,
+ 'string' => $this->load($context, $prefix),
+ 'NULL' => null,
+ };
}
/**
@@ -54,7 +47,7 @@ public function __construct($context = null, string $prefix = null)
*/
public static function fromDirectory(string $path): ConfigInterface
{
- $config = new self();
+ $config = new self;
foreach (new DirectoryIterator($path) as $file) {
if ($file->isFile()) {
@@ -93,7 +86,7 @@ public function set(string $key, mixed $value): bool
* Retrieve a configuration option via a provided key.
*
* @param string $key Unique configuration option key
- * @param mixed|null $default Default value to return if option does not exist
+ * @param mixed $default Default value to return if option does not exist
*
* @return mixed Stored config item or $default value
*/
@@ -138,10 +131,9 @@ public function has(string $key): bool
* @param string $key Unique configuration option key
* @param mixed $value Config item value
*
- * @return true
- *
* @throws RuntimeException
*
+ * @return true
*/
public function append(string $key, mixed $value): bool
{
@@ -166,10 +158,9 @@ public function append(string $key, mixed $value): bool
* @param string $key Unique configuration option key
* @param mixed $value Config item value
*
- * @return true
- *
* @throws RuntimeException
*
+ * @return true
*/
public function prepend(string $key, mixed $value): bool
{
@@ -221,6 +212,7 @@ public function load(string $path, string $prefix = null, bool $override = true)
$className = $file->isDir() ? 'Directory' : ucfirst(strtolower($file->getExtension()));
$classPath = 'PHLAK\\Config\\Loaders\\' . $className;
+ /** @var Loader $loader */
$loader = new $classPath($file->getRealPath());
$newConfig = $prefix ? [$prefix => $loader->getArray()] : $loader->getArray();
@@ -259,12 +251,17 @@ public function merge(ConfigInterface $config, bool $override = true): ConfigInt
*
* @param string $key Unique configuration option key
*
- * @return \PHLAK\Config\Interfaces\ConfigInterface A new ConfigInterface object
- * @throws InvalidContextException
+ * @return ConfigInterface A new ConfigInterface object
*/
public function split(string $key): ConfigInterface
{
- return new self($this->get($key));
+ $value = $this->get($key);
+
+ if (! is_array($value)) {
+ throw new RuntimeException(sprintf('Config item [%s] is not an array', $key));
+ }
+
+ return new self($value);
}
/**
diff --git a/src/Exceptions/ConfigException.php b/src/Exceptions/ConfigException.php
index d9252c8..ce606ff 100644
--- a/src/Exceptions/ConfigException.php
+++ b/src/Exceptions/ConfigException.php
@@ -4,6 +4,4 @@
use Exception;
-abstract class ConfigException extends Exception
-{
-}
+abstract class ConfigException extends Exception {}
diff --git a/src/Exceptions/InvalidContextException.php b/src/Exceptions/InvalidContextException.php
deleted file mode 100644
index 29a8466..0000000
--- a/src/Exceptions/InvalidContextException.php
+++ /dev/null
@@ -1,7 +0,0 @@
-isDir() ? 'Directory' : ucfirst(strtolower($file->getExtension()));
$classPath = 'PHLAK\\Config\\Loaders\\' . $className;
+ /** @var Loader $loader */
$loader = new $classPath($file->getPathname());
try {
$contents = array_merge($contents, $loader->getArray());
- } catch (InvalidFileException $e) {
- // Ignore it and continue
+ } catch (InvalidFileException) {
+ continue;
}
}
diff --git a/src/Loaders/Json.php b/src/Loaders/Json.php
index e9552be..ef8bfed 100644
--- a/src/Loaders/Json.php
+++ b/src/Loaders/Json.php
@@ -18,6 +18,11 @@ public function getArray(): array
{
$contents = file_get_contents($this->context);
+ if ($contents === false) {
+ throw new InvalidFileException('Unable to parse invalid JSON file at ' . $this->context);
+ }
+
+ /** @var array|null $parsed */
$parsed = json_decode($contents, true);
if (is_null($parsed)) {
diff --git a/src/Loaders/Loader.php b/src/Loaders/Loader.php
index 012c5a7..b62929e 100644
--- a/src/Loaders/Loader.php
+++ b/src/Loaders/Loader.php
@@ -2,6 +2,7 @@
namespace PHLAK\Config\Loaders;
+use PHLAK\Config\Exceptions\InvalidFileException;
use PHLAK\Config\Interfaces\Loadable;
abstract class Loader implements Loadable
@@ -22,6 +23,8 @@ public function __construct(string $context)
/**
* Retrieve the context as an array of configuration options.
*
+ * @throws InvalidFileException
+ *
* @return array Array of configuration options
*/
abstract public function getArray(): array;
diff --git a/src/Loaders/Toml.php b/src/Loaders/Toml.php
index f4be8ea..0302bd1 100644
--- a/src/Loaders/Toml.php
+++ b/src/Loaders/Toml.php
@@ -19,6 +19,7 @@ class Toml extends Loader
public function getArray(): array
{
try {
+ /** @var array $parsed */
$parsed = TomlParser::parseFile($this->context);
} catch (ParseException $e) {
throw new InvalidFileException($e->getMessage());
diff --git a/src/Loaders/Xml.php b/src/Loaders/Xml.php
index dc6b892..fda55c1 100644
--- a/src/Loaders/Xml.php
+++ b/src/Loaders/Xml.php
@@ -2,6 +2,7 @@
namespace PHLAK\Config\Loaders;
+use JsonException;
use PHLAK\Config\Exceptions\InvalidFileException;
class Xml extends Loader
@@ -18,10 +19,19 @@ public function getArray(): array
{
$parsed = @simplexml_load_file($this->context);
- if (! $parsed) {
+ if ($parsed === false) {
throw new InvalidFileException('Unable to parse invalid XML file at ' . $this->context);
}
- return json_decode(json_encode($parsed), true);
+ try {
+ $json = json_encode($parsed, flags: JSON_THROW_ON_ERROR);
+ } catch (JsonException $exception) {
+ throw new InvalidFileException(previous: $exception);
+ }
+
+ /** @var array $array */
+ $array = json_decode($json, true);
+
+ return $array;
}
}
diff --git a/src/Loaders/Yaml.php b/src/Loaders/Yaml.php
index 705fb35..b7b98fc 100644
--- a/src/Loaders/Yaml.php
+++ b/src/Loaders/Yaml.php
@@ -18,10 +18,16 @@ class Yaml extends Loader
*/
public function getArray(): array
{
+ $contents = file_get_contents($this->context);
+
+ if ($contents === false) {
+ throw new InvalidFileException(sprintf('Unable to parse file [%s]', $this->context));
+ }
+
try {
- $parsed = YamlParser::parse(file_get_contents($this->context));
- } catch (ParseException $e) {
- throw new InvalidFileException($e->getMessage());
+ $parsed = YamlParser::parse($contents);
+ } catch (ParseException $exception) {
+ throw new InvalidFileException($exception->getMessage());
}
if (! is_array($parsed)) {
diff --git a/src/Traits/Arrayable.php b/src/Traits/Arrayable.php
index 150ad17..b79fff9 100644
--- a/src/Traits/Arrayable.php
+++ b/src/Traits/Arrayable.php
@@ -20,11 +20,9 @@ public function getIterator(): Traversable
/**
* Determine whether an item exists at a specific offset.
*
- * @param int $offset Offset to check for existence
- *
- * @return bool
+ * @param mixed $offset Offset to check for existence
*/
- public function offsetExists($offset): bool
+ public function offsetExists(mixed $offset): bool
{
return isset($this->config[$offset]);
}
@@ -32,11 +30,9 @@ public function offsetExists($offset): bool
/**
* Retrieve an item at a specific offset.
*
- * @param int $offset Position of character to get
- *
- * @return mixed
+ * @param mixed $offset Position of character to get
*/
- public function offsetGet($offset): mixed
+ public function offsetGet(mixed $offset): mixed
{
return $this->config[$offset];
}
diff --git a/tests/ArrayTest.php b/tests/ArrayTest.php
index 9385fbf..b6b06b7 100644
--- a/tests/ArrayTest.php
+++ b/tests/ArrayTest.php
@@ -8,7 +8,7 @@
/** @covers \PHLAK\Config\Traits\Arrayable */
class ArrayTest extends TestCase
{
- public function test_it_can_initialize_an_array()
+ public function test_it_can_initialize_an_array(): void
{
$config = new Config(['foo' => ['bar' => 'foobar']]);
@@ -16,7 +16,7 @@ public function test_it_can_initialize_an_array()
$this->assertEquals('foobar', $config->get('foo.bar'));
}
- public function test_it_can_initialize_an_array_with_a_prefix()
+ public function test_it_can_initialize_an_array_with_a_prefix(): void
{
$config = new Config(['foo' => ['bar' => 'foobar']], 'baz');
diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php
index 776654a..0c3ff66 100644
--- a/tests/ConfigTest.php
+++ b/tests/ConfigTest.php
@@ -3,7 +3,6 @@
namespace PHLAK\Config\Tests;
use PHLAK\Config\Config;
-use PHLAK\Config\Exceptions\InvalidContextException;
use PHLAK\Config\Interfaces\ConfigInterface;
use RuntimeException;
use Yoast\PHPUnitPolyfills\TestCases\TestCase;
@@ -13,71 +12,71 @@ class ConfigTest extends TestCase
{
public function test_it_is_instantiable(): void
{
- $config = new Config();
+ $config = new Config;
$this->assertInstanceOf(ConfigInterface::class, $config);
}
- public function test_it_can_set_and_retrieve_an_item()
+ public function test_it_can_set_and_retrieve_an_item(): void
{
- $config = new Config();
+ $config = new Config;
$this->assertTrue($config->set('name', 'John Pinkerton'));
$this->assertEquals('John Pinkerton', $config->get('name'));
}
- public function test_it_can_set_and_retrieve_an_item_by_dot_notation()
+ public function test_it_can_set_and_retrieve_an_item_by_dot_notation(): void
{
- $config = new Config();
+ $config = new Config;
$this->assertTrue($config->set('foo.bar.baz', 'foo-bar-baz'));
$this->assertEquals('foo-bar-baz', $config->get('foo.bar.baz'));
$this->assertEquals(['baz' => 'foo-bar-baz'], $config->get('foo.bar'));
}
- public function test_it_returns_null_for_nonexistant_items()
+ public function test_it_returns_null_for_nonexistant_items(): void
{
- $config = new Config();
+ $config = new Config;
$this->assertNull($config->get('nonexistant-item'));
}
- public function test_it_returns_a_default_value_for_nonexistant_items()
+ public function test_it_returns_a_default_value_for_nonexistant_items(): void
{
- $config = new Config();
+ $config = new Config;
$this->assertFalse($config->get('nonexistant-item', false));
}
- public function test_it_returns_true_if_it_has_an_item()
+ public function test_it_returns_true_if_it_has_an_item(): void
{
$config = new Config(['has' => 'some-item']);
$this->assertTrue($config->has('has'));
}
- public function test_it_returns_true_if_it_has_a_boolean_false()
+ public function test_it_returns_true_if_it_has_a_boolean_false(): void
{
$config = new Config(['false' => false]);
$this->assertTrue($config->has('false'));
}
- public function test_it_returns_false_if_it_doesnt_have_an_item()
+ public function test_it_returns_false_if_it_doesnt_have_an_item(): void
{
- $config = new Config();
+ $config = new Config;
$this->assertFalse($config->has('nonexistant-item'));
}
- public function test_it_returns_true_if_it_has_an_item_by_dot_notation()
+ public function test_it_returns_true_if_it_has_an_item_by_dot_notation(): void
{
$config = new Config(['foo' => ['bar' => 'foobar']]);
$this->assertTrue($config->has('foo.bar'));
}
- public function test_it_can_load_and_read_additional_files()
+ public function test_it_can_load_and_read_additional_files(): void
{
$config = new Config(['driver' => 'sqlite']);
@@ -86,16 +85,16 @@ public function test_it_can_load_and_read_additional_files()
$this->assertEquals('mysql', $config->get('driver'));
}
- public function test_it_can_load_additonal_files_with_a_prefix()
+ public function test_it_can_load_additonal_files_with_a_prefix(): void
{
- $config = new Config();
+ $config = new Config;
$config->load(__DIR__ . '/files/php/config.php', 'database');
$this->assertEquals('mysql', $config->get('database.driver'));
}
- public function test_it_can_load_additional_files_without_overriding_existing_options()
+ public function test_it_can_load_additional_files_without_overriding_existing_options(): void
{
$config = new Config(['driver' => 'sqlite']);
@@ -104,7 +103,7 @@ public function test_it_can_load_additional_files_without_overriding_existing_op
$this->assertEquals('sqlite', $config->get('driver'));
}
- public function test_it_can_merge_a_config_object()
+ public function test_it_can_merge_a_config_object(): void
{
$config = new Config(['foo' => 'foo', 'baz' => 'baz']);
$gifnoc = new Config(['bar' => 'rab', 'baz' => 'zab']);
@@ -116,7 +115,7 @@ public function test_it_can_merge_a_config_object()
$this->assertEquals('zab', $config->get('baz'));
}
- public function test_it_can_merge_a_config_object_without_overriding_existing_values()
+ public function test_it_can_merge_a_config_object_without_overriding_existing_values(): void
{
$config = new Config(['foo' => 'foo', 'baz' => 'baz']);
$gifnoc = new Config(['bar' => 'rab', 'baz' => 'zab']);
@@ -128,7 +127,7 @@ public function test_it_can_merge_a_config_object_without_overriding_existing_va
$this->assertEquals('baz', $config->get('baz'));
}
- public function test_it_can_split_into_a_sub_object()
+ public function test_it_can_split_into_a_sub_object(): void
{
$config = new Config([
'foo' => 'foo',
@@ -143,16 +142,9 @@ public function test_it_can_split_into_a_sub_object()
$this->assertNull($bar->get('foo'));
}
- public function test_it_throws_an_exception_when_initialized_with_an_invalid_context()
+ public function test_it_can_set_and_retrieve_a_closure(): void
{
- $this->expectException(InvalidContextException::class);
-
- new Config(123);
- }
-
- public function test_it_can_set_and_retrieve_a_closure()
- {
- $config = new Config();
+ $config = new Config;
$config->set('closure', function ($foo) {
return ucwords($foo);
@@ -164,7 +156,7 @@ public function test_it_can_set_and_retrieve_a_closure()
$this->assertEquals('John Pinkerton', $closure('john pinkerton'));
}
- public function test_it_can_be_handled_like_an_array()
+ public function test_it_can_be_handled_like_an_array(): void
{
$config = new Config(['foo' => 'foo', 'bar' => 'bar']);
$config['baz'] = 'baz';
@@ -176,7 +168,7 @@ public function test_it_can_be_handled_like_an_array()
$this->assertEquals('baz', $config['baz']);
}
- public function test_it_can_be_returned_as_an_array()
+ public function test_it_can_be_returned_as_an_array(): void
{
$config = new Config([
'foo' => 'foo',
@@ -193,7 +185,7 @@ public function test_it_can_be_returned_as_an_array()
], $config->toArray());
}
- public function test_it_is_foreachable()
+ public function test_it_is_foreachable(): void
{
$config = new Config([
'foo' => true,
@@ -208,7 +200,7 @@ public function test_it_is_foreachable()
}
}
- public function test_it_can_append_values_to_an_array_item()
+ public function test_it_can_append_values_to_an_array_item(): void
{
$config = new Config([
'app' => [
@@ -227,7 +219,7 @@ public function test_it_can_append_values_to_an_array_item()
], $config->get('app.vars'));
}
- public function test_it_throws_an_error_when_appending_to_a_non_array_item()
+ public function test_it_throws_an_error_when_appending_to_a_non_array_item(): void
{
$config = new Config(['foo' => 'foo']);
@@ -236,7 +228,7 @@ public function test_it_throws_an_error_when_appending_to_a_non_array_item()
$config->append('foo', 'bar');
}
- public function test_it_can_prepend_values_to_an_array_item()
+ public function test_it_can_prepend_values_to_an_array_item(): void
{
$config = new Config([
'app' => [
@@ -255,7 +247,7 @@ public function test_it_can_prepend_values_to_an_array_item()
], $config->get('app.vars'));
}
- public function test_it_throws_an_error_when_prepending_to_a_non_array_item()
+ public function test_it_throws_an_error_when_prepending_to_a_non_array_item(): void
{
$config = new Config(['foo' => 'foo']);
@@ -264,7 +256,7 @@ public function test_it_throws_an_error_when_prepending_to_a_non_array_item()
$config->prepend('foo', 'bar');
}
- public function test_it_can_be_instantiated_with_prefixes()
+ public function test_it_can_be_instantiated_with_prefixes(): void
{
$config = Config::fromDirectory(__DIR__ . '/prefix_test');
diff --git a/tests/DirectoryTest.php b/tests/DirectoryTest.php
index 5a841f1..45f179f 100644
--- a/tests/DirectoryTest.php
+++ b/tests/DirectoryTest.php
@@ -8,7 +8,7 @@
/** @covers \PHLAK\Config\Loaders\Directory */
class DirectoryTest extends TestCase
{
- public function test_it_can_initialize_a_directory()
+ public function test_it_can_initialize_a_directory(): void
{
$config = new Config(__DIR__ . '/files');
@@ -16,7 +16,7 @@ public function test_it_can_initialize_a_directory()
$this->assertEquals('mysql', $config->get('driver'));
}
- public function test_it_can_initialize_an_array_with_a_prefix()
+ public function test_it_can_initialize_an_array_with_a_prefix(): void
{
$config = new Config(__DIR__ . '/files', 'database');
diff --git a/tests/TomlTest.php b/tests/TomlTest.php
index e0f0292..e1962ec 100644
--- a/tests/TomlTest.php
+++ b/tests/TomlTest.php
@@ -18,7 +18,7 @@ protected function setUp(): void
$this->invalidConfig = __DIR__ . '/files/toml/invalid.toml';
}
- public function test_it_throws_an_exception_when_initializing_a_toml_file_without_an_array()
+ public function test_it_throws_an_exception_when_initializing_a_toml_file_without_an_array(): void
{
$this->expectException(InvalidFileException::class);
diff --git a/tests/Traits/Initializable.php b/tests/Traits/Initializable.php
index f4dc38c..ec8a75e 100644
--- a/tests/Traits/Initializable.php
+++ b/tests/Traits/Initializable.php
@@ -14,7 +14,7 @@ trait Initializable
/** @var string Path to an invalid config file */
protected $invalidConfig;
- public function test_it_can_initialize_a_file()
+ public function test_it_can_initialize_a_file(): void
{
$config = new Config($this->validConfig);
@@ -22,7 +22,7 @@ public function test_it_can_initialize_a_file()
$this->assertEquals('database.sqlite', $config->get('drivers.sqlite.database'));
}
- public function test_it_throws_an_exception_when_initializing_an_invalid_file()
+ public function test_it_throws_an_exception_when_initializing_an_invalid_file(): void
{
$this->expectException(ConfigException::class);
$this->expectException(InvalidFileException::class);
@@ -30,7 +30,7 @@ public function test_it_throws_an_exception_when_initializing_an_invalid_file()
new Config($this->invalidConfig);
}
- public function test_it_can_initialize_a_file_with_a_prefix()
+ public function test_it_can_initialize_a_file_with_a_prefix(): void
{
$config = new Config($this->validConfig, 'database');
diff --git a/tests/YamlTest.php b/tests/YamlTest.php
index 3dfbc3a..78e26b4 100644
--- a/tests/YamlTest.php
+++ b/tests/YamlTest.php
@@ -18,7 +18,7 @@ protected function setUp(): void
$this->invalidConfig = __DIR__ . '/files/yaml/invalid.yaml';
}
- public function test_it_throws_an_exception_when_initializing_a_yaml_file_without_an_array()
+ public function test_it_throws_an_exception_when_initializing_a_yaml_file_without_an_array(): void
{
$this->expectException(InvalidFileException::class);