The deprecated spelling LamiasConfigAggregatorConfig
has been removed. Replace imports, type declarations, and instantiations with LaminasConfigAggregatorConfig
; there is no autoload alias fallback.
Interfaces And Classes
The package exposes a small set of public types. Most users touch only the factory functions and ConfigInterface
, but the concrete classes are available when you need explicit behavior.
| Type | Responsibility | Use when |
|---|---|---|
ConfigInterface
|
Common contract for reading, writing, iterating, and exporting configuration. | You want to depend on an abstraction. |
ArrayConfig
|
In-memory config storage with dot-notation support. | Your config already exists as an array or you are writing tests. |
AggregateConfig
|
Lazy merger for several ConfigInterface
sources. |
You want one config built from many existing config objects. |
DirectoryConfig
|
Lazy loader for top-level PHP files in one directory. | Your config lives in one directory and you do not want recursion. |
RecursiveDirectoryConfig
|
Lazy loader for PHP files in a directory tree. | Your config is split across nested folders. |
PhpFileConfig
|
Lazy loader for a single PHP file with optional persistence. | Your config is stored in a single PHP file, or you want write-through changes. |
LaminasConfigAggregatorConfig
|
Bridge to Laminas ConfigAggregator. | You want provider-based aggregation directly. |
CachedConfig
|
PSR-16 cache wrapper around another config source. | You need cache integration or custom cache-key behavior. |
ConfigContainer
|
PSR-11 container wrapper for config access. | Another part of your system expects ContainerInterface
. |
ConfigInterface
ConfigInterface
defines the shared behavior across all config implementations:
has(string $key): boolget(string $key, mixed $default = null): mixedset(array|ConfigInterface|string $key, mixed $value = null): voidremove(string $key): voidtoArray(): array
It also extends IteratorAggregate
and ArrayAccess
, so config objects can be iterated and accessed like arrays.
ArrayConfig
ArrayConfig
is the simplest concrete implementation:
- It normalizes associative arrays so dot-notated keys become nested arrays.
get()returns anotherArrayConfigfor associative subtrees.- Sequential lists remain regular PHP arrays.
- Iteration yields flattened dot-notated keys.
AggregateConfig
AggregateConfig
merges several ConfigInterface
instances into one lazily resolved config. Later sources override earlier values for the same key while preserving unrelated nested values.
DirectoryConfig And RecursiveDirectoryConfig
These classes load PHP files from disk:
DirectoryConfigscans only the top level of the target directory.RecursiveDirectoryConfigscans nested subdirectories at every depth.- Both validate that the directory exists and is readable.
- Both support an optional cache file path through Laminas ConfigAggregator.
Generating that file also requires a truthy config_cache_enabled
entry in a
loaded PHP configuration array and an existing, writable parent directory. Keep
the cache outside the scanned source directory. An existing cache file is reused
before loading source files. See Caching.
Directory paths are treated literally, including characters such as brackets and braces. The protected PATTERN
constant controls filename selection; overriding it continues to use the existing glob and brace-order semantics.
Selected files are included through their resolved absolute paths. Relative directory roots therefore cannot be redirected through PHP's include_path
or configuration files that change the working directory during loading.
Discovery stays lazy. Root files are loaded before files one directory below, then files two directories below, and so on. Within each level, directories are ordered by their paths and the filename pattern determines the order inside each directory. The default patterns therefore produce deterministic path ordering while preserving later-value overrides and sequential-list concatenation.
Child directory symlinks are not followed, so aliases and recursive cycles do not duplicate traversal. Hidden child directories are skipped. File symlinks may be loaded, but every resolved file is included only once; its first discovered path determines its merge position. A root directory explicitly supplied by the caller may itself be a symlink.
Recursive traversal skips child directories that are unreadable or disappear before they can be opened. Accessible configuration still loads. Root read failures and unrelated filesystem or configuration-file errors remain visible.
Existing generated cache files bypass discovery. Invalidate or rebuild them after upgrading if they were created while deeper configuration files were omitted.
PhpFileConfig
PhpFileConfig
loads configuration from a single PHP file returning an array.
Important constructor options:
file: path to the PHP configuration file.persistent: whetherset()andremove()should write changes back to the PHP file.defaultConfig: optional default configuration used when the file does not yet exist.
Relative inputs are anchored to an absolute location on first use, independently of PHP's
include_path
. Later working-directory changes do not move the instance to another file.
Inputs containing ://
select a stream only when their leading protocol matches PHP's
registered wrappers. Nested URI-like components, single-character prefixes and unregistered
protocols retain PHP's filesystem fallback and are anchored to their initial directory.
Each persistent mutation refreshes PHP's path caches before following the current symlink
chain from that location, including directory links changed by another process. It uses the
same resolved target for its lock, fresh read, and atomic replacement. Symlink chains are
followed to the final target, including a missing target created from defaultConfig
.
This also applies when a parent-directory link points to a directory that does not yet exist.
Cyclic or excessively long chains raise
FastForward\\Config\\Exception\\InvalidArgumentException
before any link is replaced.
On POSIX, symlink targets are literal filesystem paths: ://
in a relative target does
not select a stream wrapper. Unavailable PHP functions required to resolve a path also raise
InvalidArgumentException
before any persistent change.
Trailing directory separators retain their native meaning, including when supplied by a
symlink target. A path such as settings.php/
cannot silently select settings.php
.
Paths containing NUL bytes retain missing-file read behavior, including defaults when
provided. Persistent mutations reject these paths with InvalidArgumentException
before
creating directories, locks, or files.
Atomic replacements preserve existing permission bits and, on POSIX systems, the existing
file's group. If the group or permissions cannot be applied to the temporary file, including
when required metadata functions are disabled, the mutation raises InvalidArgumentException
and leaves the original file intact. New files use
0666 & ~umask()
and the filesystem's default creation group. Windows does not attempt POSIX
group reassignment; its native permission behavior applies.
On Windows, single-separator rooted paths such as \settings.php
or /settings.php
are anchored to the initial drive or UNC volume on first use. Fully qualified drive,
UNC, and DOS device paths retain their supplied root.
Drive-relative paths such as C:settings.php
use native PHP resolution when available.
Supported inputs are anchored to their drive's directory while retaining their relative
suffix, so later symlink retargeting still applies.
If such a path cannot be resolved, including an existing path unsupported by native PHP, it raises
InvalidArgumentException
before creating directories, locks, or files. Use a
fully qualified path such as C:\app\settings.php
when creating a new target.
LaminasConfigAggregatorConfig
This class is the direct bridge around Laminas\\ConfigAggregator\\ConfigAggregator
. Use it when you want provider-based config aggregation without going through the helper functions.
cachedConfigFile
selects a cache file. If it already exists, it is loaded
before providers execute. Generating a missing cache file also requires a truthy
ConfigAggregator::ENABLE_CACHE
(config_cache_enabled
) value in merged
provider output and an existing, writable parent directory. Passing null
bypasses file caching; a false enabling flag alone does not bypass an existing file.
CachedConfig
CachedConfig
wraps another ConfigInterface
and stores the resolved array in a PSR-16 cache backend.
Important constructor options:
cache: the PSR-16 cache backend.defaultConfig: the wrapped config source.persistent: whetherset()andremove()should write back to the cache backend.cacheKey: optional application-owned key for cross-instance reuse with the backend's default lifetime. Without one, each wrapper uses its own portable PSR-16 key and every write expires after 300 seconds.
Cache misses and non-array entries fall back to the source without requiring a successful cache write or readback. Cache hits leave the source unresolved. Persistent mutations raise RuntimeException
when the backend returns false
from set()
; the local mutation is retained. See Caching for migration and invalidation details.
ConfigContainer
ConfigContainer
adapts a config object to PSR-11. It resolves these identifiers:
configreturns the wrapped config object.FastForward\\Config\\ConfigInterfacereturns the wrapped config object.- The concrete config class name returns the wrapped config object.
config.some.keyreturns a single configuration value.FastForward\\Config\\Container\\ConfigContainerreturns the container wrapper itself.
Unknown identifiers raise ContainerNotFoundException
.