Download the PHP package dvictorjhg/php-injector without Composer
On this page you can find all versions of the php package dvictorjhg/php-injector. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download dvictorjhg/php-injector
More information about dvictorjhg/php-injector
Files in dvictorjhg/php-injector
Package php-injector
Short Description Reflection-based dependency injection and PSR-11 container for modern PHP.
License Apache-2.0
Homepage https://github.com/dvictorjhg/php-injector
Informations about the package php-injector
PHPInjector
PHPInjector is a small reflection-based dependency injection package for modern PHP. It gives you a PSR-11 compatible container, a lightweight injector, a parameter attribute for explicit value binding, and a self-managed singleton contract without forcing a large framework around your code.
PHPInjector exists for projects that want constructor and method injection without adopting a full application container, a framework-specific service graph, or a code-generation step. The package stays close to native PHP features such as reflection, attributes, and simple arrays so it remains easy to read, debug, and embed in small or medium-sized codebases.
Documentation
The PHPInjector documentation page covers installation, injection targets, provider lifecycles, parameter resolution, the public API, and executable recipes. The responsive static site defaults to English and the light theme, with English/Spanish and theme preferences in the header. All guide content is readable without JavaScript.
Run each complete PHP example independently from the project root after installing dependencies. Examples reuse class names and are not intended to be combined into one file. Every complete example includes the Composer autoloader.
Why Use PHPInjector
- Small surface area and low ceremony.
- Works with classes, methods, closures, invokable objects, global functions, and callable strings.
- Supports PSR-11 container access for simple provider storage.
- Allows lazy class registration, concrete instances, alias-style mappings, and named scalar values.
- Supports scalar or contextual values through explicit arguments or
#[Inject]. - Supports provider composition through parent injectors.
- Supports singleton-style providers through a dedicated contract.
- Uses implicit singleton caching by default, with a class-level
#[Transient]attribute for opt-in transient resolution. - Provides
Injector::inject()andPHPInjector\DI\inject()global entry points backed by the active injector staircase.
Requirements
- PHP 8.3+
- Composer
Installation
Install the package:
Quick Start
The examples below stay in the same small reporting domain and add one feature at a time.
Example #1 Resolve a class with constructor injection
Expected output:
Injector::inject() and PHPInjector\DI\inject() use the most recently constructed injector. If no injector exists yet, the first call creates a default injector. When a new Injector is created without an explicit parent, the previously active injector becomes its parent, forming a provider staircase.
For the function form, import it once with use function PHPInjector\DI\inject; and call inject(...) after creating the application's first injector.
Usage
Example #2 Register providers in the common forms
You can register a lazy class, an alias mapping, a prebuilt object, and a named scalar value in one injector:
Expected output:
Class-string providers and alias mappings are instantiated lazily and cached after first resolution unless the resolved class uses #[Transient]. Aliases and direct class resolution share the cached instance for the same automatically resolved concrete class.
Inherited aliases resolve within the injector that registered them, for both direct requests and typed parameters. A child alias can reuse a concrete instance already cached in its parent unless the child overrides that concrete provider.
Example #3 Inject methods and other callables
PHPInjector can resolve more than constructors. The next example uses an instance method, a closure, and a callable string:
Expected output:
Callables can be provided as closures, array callables, callable strings, global function names, or first-class callables.
The built-in strlen example in Resolution order demonstrates
parameter-name arguments for a global function.
Example #4 Bind scalar values explicitly
Scalar values can be passed directly per call when no provider should supply them:
Expected output:
Use one argument style per call. The injector accepts values by type key, parameter name, or numeric position, but it rejects mixed-key arrays.
Example #5 Use #[Inject] for named values
When a scalar or context value should come from the injector, bind it explicitly with the attribute:
Expected output:
Example #6 Use the Singleton contract for self-managed providers
If a provider implements PHPInjector\Contracts\Singleton, the injector calls getInstance() instead of the constructor:
Expected output:
The Singleton contract is appropriate when a class must own its creation policy. In this example, the private constructor and getInstance() implementation enforce uniqueness independently of injector-managed caching.
Example #7 Opt into transient resolution with #[Transient]
Classes use injector-managed singleton caching by default. Add #[Transient] to skip that automatic cache and receive a fresh instance whenever resolution reaches the class constructor:
Expected output:
Unlike the Singleton contract, the #[Transient] attribute is an injector-managed opt-out from the default cache. Each injector has its own local cache, while a newly constructed injector can continue provider lookup through the active injector staircase.
The attribute does not override an explicitly supplied provider object or a class's Singleton::getInstance() implementation. Static injection always uses the most recently constructed injector.
Example #8 Compose providers with a parent injector
A child injector checks its own providers first and then continues through its parent chain:
Expected output:
The child owns the automatically constructed ReportService; its Logger dependency is found through the parent provider chain.
Example #9 Inject a closure and a variadic list
Named non-builtin types can use providers keyed by their type. A Closure provider can be selected by Closure::class, and an array-valued provider is expanded for a variadic parameter:
Expected output:
Resolution order
Same dependency, three valid forms
In Injector::inject($target, $args), $args is the optional map of values supplied for one injection call. It is separate from the reusable provider map passed to new Injector([...]); the target still declares its own parameters, and PHPInjector uses the $args keys to match them.
For a target with a Logger $logger parameter, these three calls pass the same value and print the same result. Choose one key style per call:
Expected output:
Do not combine key styles in one $args array. PHPInjector rejects mixed integer and string keys before it invokes the target; the array is not a fallback list:
Expected failure output:
The same meaning applies when the target is a PHP built-in callable:
Expected output:
Here, string names strlen's parameter, while $args remains the second argument to Injector::inject().
For each parameter, PHPInjector starts at step 1 and stops at the first successful match:
- Explicit per-call arguments: check the type key, then the parameter name, then numeric position.
#[Inject('id')]attribute lookup, only when no explicit argument matched.- Registered provider lookup for a supported non-builtin named parameter type.
- PHP default parameter value, when one exists.
InjectorExceptionwhen the required parameter is still unresolved.
Step 1 has its own internal precedence. When you pass $args as the second argument to Injector::inject(), PHPInjector checks it in this order for each parameter:
- Type key for a supported non-builtin named type, for example
Logger::class => $logger. - Parameter name, for example
'logger' => $logger. - Numeric position for a non-variadic parameter, for example
[0 => $logger].
Use one argument style per call. Mixed-key arrays such as [Logger::class => $logger, 0 => $fallback] are rejected.
When step 2 or 3 runs, provider lookup checks the active injector first and then walks up the parent injector staircase until a matching provider is found or the chain ends. Passing an explicit parent to the constructor overrides the automatic parent selection.
Automatic type-based lookup supports registered non-builtin named types, including concrete classes, interfaces, abstract classes, enum instances, nullable named types, and Closure providers registered under Closure::class. Built-in types, callable, untyped parameters, and union, intersection, or DNF types require an explicit value in the per-call $args map, a named provider through #[Inject('id')], or a PHP default. The injector does not choose between multiple compound-type candidates automatically.
Variadic parameters accept zero or more values. Numeric values from the variadic parameter's position onward are collected, and an array-valued provider is expanded into individual arguments.
Parameter resolution flow
Explicit argument precedence
Full resolution example
Expected output:
In that call:
- In the first call,
string $reportis resolved from the explicit per-call argument. #[Inject('env')] string $environmentis resolved from the named provider.Logger $loggeris resolved from the typed provider lookup.- In the second call,
string $reporthas no explicit value, so its PHP default,summary, is used. $tokenhas no argument,#[Inject]provider, typed provider, or default, so PHPInjector throwsInjectorException.
Container Support
The package includes PHPInjector\Container\Container, a PSR-11 compatible container for direct storage and retrieval of providers. It is intentionally small and can also be used without the injector when all you need is provider registration and lookup.
get(string $id)returns the stored value unchanged, including class strings and closures. It does not construct or execute providers.has(string $id)returns true for present entries, even when the value is null.set(string $id, mixed $value)replaces an entry;unset(string $id)removes it.count()and iteration expose the locally stored entries, not an injector's parent chain.- Missing entries throw
PHPInjector\Container\NotFoundException, implementing PSR-11'sNotFoundExceptionInterface. Duplicate normalized identifiers or invalid list-style values throwContainerException.
See the verified container recipe.
Boundaries And Troubleshooting
- A typed constructor parameter is unresolved: register that type, map its interface to a concrete class, or supply an explicit argument. Resolving a class target directly does not recursively autowire unregistered parameter types.
- A closure provider did not run: providers are values, not factories.
Invoke the injected closure in your consumer, or pass a callable as the target
of
Injector::inject()to execute it with resolved arguments. - New constructor arguments had no effect: the class may already be cached.
Use
#[Transient]or explicitly supply a dependency object when fresh identity is required. Registered objects are always returned as supplied. - Old providers are still visible: the newest injector is globally active; an omitted or null parent links to the previous injector. There is no public reset, isolated-root switch, or request-scoped container API.
- Circular graphs: recursive construction raises
InjectorExceptioninstead of exhausting the PHP stack or memory. Resolution state is cleared after failure, so correcting a provider or supplying an explicit dependency allows retry. - Long-running workers: do not retain request-specific data in cached
services. A class-managed
Singleton::getInstance()is not reset by the injector. - Public API: use
new Injector(...),$injector->addProvider(...),Injector::inject(...), or theinject(...)function.getProvider()is private and there is no publichasProvider()method. UseContainerfor directget()/has()access.
Quality
CI also runs php tools/check-docs.php on PHP 8.5 to verify executable examples.
The main CI workflow in Codecov, and fail the build if statement coverage drops below 80%.
Before the first upload, enable the repository in Codecov. Public pull requests from forks can upload from an unprotected branch without a token, but uploads for protected branches and all private repositories require a Codecov token unless token authentication for public repositories has been disabled in Codecov's Global Upload Token settings. For the reliable protected-branch path, add the repository token as a GitHub Actions secret named CODECOV_TOKEN under Settings > Secrets and variables > Actions. Keep it in GitHub Secrets rather than committing it to the repository. If the repository is private, copy the tokenized badge URL from Codecov's Badges & Graphs settings and replace the badge image URL above.
Tooling
- GitHub Actions for continuous integration, with actions/checkout to fetch the repository and shivammathur/setup-php to provision supported PHP runtimes with Xdebug coverage support.
- Codecov for the coverage report and README badge, uploaded through codecov/codecov-action with tokenless public-branch support and a GitHub Actions secret for protected-branch uploads.
- Composer for dependency management, package metadata validation, dependency installation, and project scripts such as
composer analyse,composer test, andcomposer test:coverage. - PHPStan for static analysis, executed through
composer analyse. - PHPUnit for the unit test suite and Clover coverage report generation through
composer test:coverage. - Xdebug for code coverage in CI and local coverage runs.
- tools/check-coverage.php for enforcing a configurable statement coverage threshold, defaulting to 80%, from a Clover XML report.
Local Development
Install dependencies and run the test suite:
To run the same coverage checks enforced in CI:
The documentation check needs PHP DOM and proc_open. It executes marked HTML
examples and README examples with expected output in isolated PHP processes and
compares exact output. Xdebug is disabled only in these child processes so
var_dump() produces standard PHP output. Coverage runs need Xdebug or PCOV.
Customize Development Tools
Composer forwards arguments after --. The coverage checker defaults to
build/test-results/clover.xml and 80%. To override it, supply both the report
path and a finite percentage between 0 and 100:
Select your own configuration files using the same flags. To customize coverage
output, run vendor/bin/phpunit --coverage-clover /tmp/clover.xml with a coverage
driver enabled, then pass that file to the checker. These development settings
do not affect provider caching or injection behavior; configure those through
provider registrations, explicit arguments, #[Inject], and #[Transient].
Contributing
Contributions are welcome. Start with CONTRIBUTING.md for setup, test expectations, and pull request guidance.
GitHub issue forms and a pull request template are included to keep reports and reviews consistent.
Security
Please report vulnerabilities privately as described in SECURITY.md.
Changelog
Release notes live in CHANGELOG.md.
Release / Publishing
For each release, finalize the dated entry in
CITATION.cff and the English
and Spanish documentation version labels, then run composer validate --strict,
composer check-platform-reqs, php tools/check-docs.php, composer analyse,
composer test:coverage, and composer coverage:check. Review composer audit
and inspect a composer archive build before creating the annotated version tag.
No tag, push, or publication is part of local release preparation.
After the tag is on GitHub, publish a GitHub Release and refresh Packagist.
Packagist reads versions from Git tags, so do not add a version field to
composer.json. Verify the intended version constraint in a clean application
before publishing a dependent BraidPHP release. Release-specific behavior belongs
in the changelog.
License And Attribution
This project is licensed under Apache-2.0. That keeps the project open-source while requiring preservation of the license text, copyright notice, and repository notices in redistributions.
For academic, professional, blog, package, or product reuse, keep attribution intact and link back to the original repository when reasonable. The bundled CITATION.cff files make that straightforward.
AI Use Policy
The maintainer wants this project credited when it is reused and does not want it stripped of attribution or turned into low-quality AI-generated derivative spam. That expectation is documented in AI_USE_POLICY.md.
Important: that policy is intentionally documented as project guidance, not as an extra open-source restriction. If you need enforceable no-AI or no-training terms, you would need a source-available non-open-source license instead.