Showing preview only (343K chars total). Download the full file or copy to clipboard to get everything.
Repository: ray-di/Ray.Di
Branch: 2.x
Commit: 13700a23ca7d
Files: 311
Total size: 279.0 KB
Directory structure:
gitextract_o85d1j_u/
├── .gitattributes
├── .github/
│ ├── CONTRIBUTING.md
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── feature.md
│ │ └── question.md
│ ├── SECURITY.md
│ └── workflows/
│ ├── coding-standards.yml
│ ├── continuous-integration.yml
│ ├── demo.yml
│ ├── prefer-lowest.yml
│ ├── static-analysis.yml
│ └── update-copyright-years-in-license-file.yml
├── .gitignore
├── .scrutinizer.yml
├── .sonarcloud.properties
├── CLAUDE.md
├── LICENSE
├── README.md
├── codecov.yml
├── composer-require-checker.json
├── composer.json
├── demo/
│ ├── 01a-linked-binding.php
│ ├── 01b-linked-binding-setter-injection.php
│ ├── 02-provider-binding.php
│ ├── 02a-named-by-qualifier.php
│ ├── 02b-named-by-named.php
│ ├── 03-injection-point.php
│ ├── 04-untarget-binding.php
│ ├── 05a-constructor-binding.php
│ ├── 05b-constructor-binding-setter-injection.php
│ ├── 07-assisted-injection.php
│ ├── 10-cache.php
│ ├── 11-script-injector.php
│ ├── 12-dependency-chain-error-message.php
│ ├── chain-error/
│ │ ├── A.php
│ │ ├── B.php
│ │ ├── C.php
│ │ ├── D.php
│ │ └── EInterface.php
│ ├── finder/
│ │ ├── Db.php
│ │ ├── DbFinder.php
│ │ ├── DbInterface.php
│ │ ├── Finder.php
│ │ ├── FinderInterface.php
│ │ ├── FinderModule.php
│ │ ├── MovieFinder.php
│ │ ├── MovieLister.php
│ │ ├── MovieListerInterface.php
│ │ └── Sorter.php
│ ├── run.php
│ └── tmp/
│ └── .gitkeep
├── phpcs.xml
├── phpmd.xml
├── phpstan.neon
├── phpunit.xml.dist
├── psalm.xml
├── rector.php
├── src/
│ └── di/
│ ├── AbstractModule.php
│ ├── AcceptInterface.php
│ ├── AnnotatedClass.php
│ ├── AnnotatedClassMethods.php
│ ├── Annotation/
│ │ └── ScriptDir.php
│ ├── Argument.php
│ ├── Arguments.php
│ ├── AspectBind.php
│ ├── AssistedInjectInterceptor.php
│ ├── AssistedInjectModule.php
│ ├── AssistedModule.php
│ ├── Bind.php
│ ├── BindValidator.php
│ ├── BuiltinModule.php
│ ├── CompileNullObject.php
│ ├── Container.php
│ ├── ContainerFactory.php
│ ├── Dependency.php
│ ├── DependencyFactory.php
│ ├── DependencyInterface.php
│ ├── DependencyProvider.php
│ ├── Di/
│ │ ├── Assisted.php
│ │ ├── Inject.php
│ │ ├── InjectInterface.php
│ │ ├── Named.php
│ │ ├── PostConstruct.php
│ │ ├── Qualifier.php
│ │ └── Set.php
│ ├── Exception/
│ │ ├── DirectoryNotWritable.php
│ │ ├── ExceptionInterface.php
│ │ ├── InvalidContext.php
│ │ ├── InvalidProvider.php
│ │ ├── InvalidToConstructorNameParameter.php
│ │ ├── InvalidType.php
│ │ ├── MethodInvocationNotAvailable.php
│ │ ├── NoHint.php
│ │ ├── NotFound.php
│ │ ├── SetNotFound.php
│ │ ├── Unbound.php
│ │ └── Untargeted.php
│ ├── Exception.php
│ ├── Grapher.php
│ ├── InjectableInterface.php
│ ├── InjectionPoint.php
│ ├── InjectionPointInterface.php
│ ├── InjectionPoints.php
│ ├── Injector.php
│ ├── InjectorInterface.php
│ ├── Instance.php
│ ├── Matcher/
│ │ └── AssistedInjectMatcher.php
│ ├── MethodInvocationProvider.php
│ ├── ModuleString.php
│ ├── MultiBinder.php
│ ├── MultiBinding/
│ │ ├── LazyInstance.php
│ │ ├── LazyInterface.php
│ │ ├── LazyProvider.php
│ │ ├── LazyTo.php
│ │ ├── Map.php
│ │ ├── MapProvider.php
│ │ ├── MultiBindingModule.php
│ │ └── MultiBindings.php
│ ├── Name.php
│ ├── NewInstance.php
│ ├── NullDependency.php
│ ├── NullModule.php
│ ├── NullObjectDependency.php
│ ├── ProviderInterface.php
│ ├── ProviderProvider.php
│ ├── ProviderSetModule.php
│ ├── ProviderSetProvider.php
│ ├── Scope.php
│ ├── SetContextInterface.php
│ ├── SetterMethod.php
│ ├── SetterMethods.php
│ ├── SpyCompiler.php
│ ├── Types.php
│ ├── Untarget.php
│ └── VisitorInterface.php
├── src-deprecated/
│ └── di/
│ ├── BcParameterQualifier.php
│ ├── BcStringParser.php
│ ├── EmptyModule.php
│ ├── NullCache.php
│ └── Provider.php
├── tests/
│ ├── bootstrap.php
│ ├── di/
│ │ ├── AnnotatedClassTest.php
│ │ ├── ArgumentTest.php
│ │ ├── ArgumentsTest.php
│ │ ├── AssistedTest.php
│ │ ├── BcParameterQualifierIntegrationTest.php
│ │ ├── BcParameterQualifierTest.php
│ │ ├── BcStringParserTest.php
│ │ ├── BindTest.php
│ │ ├── ContainerTest.php
│ │ ├── ContextualProviderTest.php
│ │ ├── DependencyTest.php
│ │ ├── Fake/
│ │ │ ├── Annotation/
│ │ │ │ ├── FakeInjectOne.php
│ │ │ │ ├── FakeLeft.php
│ │ │ │ ├── FakeNotQualifer.php
│ │ │ │ ├── FakeQualifierOnly.php
│ │ │ │ └── FakeRight.php
│ │ │ ├── FakeAbstractClass.php
│ │ │ ├── FakeAbstractDb.php
│ │ │ ├── FakeAnnoClass.php
│ │ │ ├── FakeAnnoInterceptor1.php
│ │ │ ├── FakeAnnoInterceptor2.php
│ │ │ ├── FakeAnnoInterceptor3.php
│ │ │ ├── FakeAnnoInterceptor4.php
│ │ │ ├── FakeAnnoInterceptor5.php
│ │ │ ├── FakeAnnoInterceptorInterface.php
│ │ │ ├── FakeAnnoMethod1.php
│ │ │ ├── FakeAnnoMethod2.php
│ │ │ ├── FakeAnnoMethod3.php
│ │ │ ├── FakeAnnoModule.php
│ │ │ ├── FakeAnnoOrderClass.php
│ │ │ ├── FakeAop.php
│ │ │ ├── FakeAopDoublyInstallModule.php
│ │ │ ├── FakeAopGrapher.php
│ │ │ ├── FakeAopGrapherModule.php
│ │ │ ├── FakeAopInstallModule.php
│ │ │ ├── FakeAopInterceptorModule.php
│ │ │ ├── FakeAopInterface.php
│ │ │ ├── FakeAopInterfaceModule.php
│ │ │ ├── FakeAopModule.php
│ │ │ ├── FakeAssistedConsumer.php
│ │ │ ├── FakeAssistedDb.php
│ │ │ ├── FakeAssistedDbModule.php
│ │ │ ├── FakeAssistedDbProvider.php
│ │ │ ├── FakeAssistedInjectConsumer.php
│ │ │ ├── FakeAssistedInjectDb.php
│ │ │ ├── FakeAssistedParamsConsumer.php
│ │ │ ├── FakeBcConstructorQualifierClass.php
│ │ │ ├── FakeBcParameterQualifierClass.php
│ │ │ ├── FakeBcParameterQualifierModule.php
│ │ │ ├── FakeBuiltin.php
│ │ │ ├── FakeCar.php
│ │ │ ├── FakeCarEngine.php
│ │ │ ├── FakeCarEngineModule.php
│ │ │ ├── FakeCarInterface.php
│ │ │ ├── FakeCarModule.php
│ │ │ ├── FakeClassInstanceBindModule.php
│ │ │ ├── FakeClassWithBcParameterQualifier.php
│ │ │ ├── FakeConcreteClass.php
│ │ │ ├── FakeConstant.php
│ │ │ ├── FakeConstantConsumer.php
│ │ │ ├── FakeConstantInterface.php
│ │ │ ├── FakeConstantModule.php
│ │ │ ├── FakeContextualModule.php
│ │ │ ├── FakeContextualProvider.php
│ │ │ ├── FakeContextualRobot.php
│ │ │ ├── FakeDoubleInterceptor.php
│ │ │ ├── FakeDoubleInterceptorInterface.php
│ │ │ ├── FakeEngine.php
│ │ │ ├── FakeEngine2.php
│ │ │ ├── FakeEngine3.php
│ │ │ ├── FakeEngineInterface.php
│ │ │ ├── FakeEngineProvider.php
│ │ │ ├── FakeEngineToProviderModule.php
│ │ │ ├── FakeFormerBindingHasPriorityModule.php
│ │ │ ├── FakeGearStickInject.php
│ │ │ ├── FakeGearStickInterface.php
│ │ │ ├── FakeGearStickProvider.php
│ │ │ ├── FakeHandle.php
│ │ │ ├── FakeHandleBar.php
│ │ │ ├── FakeHandleBarQualifier.php
│ │ │ ├── FakeHandleInterface.php
│ │ │ ├── FakeHandleProvider.php
│ │ │ ├── FakeHardtop.php
│ │ │ ├── FakeHardtopInterface.php
│ │ │ ├── FakeInjectionPoint.php
│ │ │ ├── FakeInstallModule.php
│ │ │ ├── FakeInstanceBindModule.php
│ │ │ ├── FakeInstanceBindModule2.php
│ │ │ ├── FakeInstanceBindModuleOneTo3.php
│ │ │ ├── FakeInternalTypeModule.php
│ │ │ ├── FakeInternalTypes.php
│ │ │ ├── FakeLeatherGearStick.php
│ │ │ ├── FakeLeft.php
│ │ │ ├── FakeLeftLeg.php
│ │ │ ├── FakeLegInterface.php
│ │ │ ├── FakeLogStringModule.php
│ │ │ ├── FakeMirrorInterface.php
│ │ │ ├── FakeMirrorLeft.php
│ │ │ ├── FakeMirrorRight.php
│ │ │ ├── FakeModuleInModule.php
│ │ │ ├── FakeModuleInModuleOverride.php
│ │ │ ├── FakeMultiBindingAnnotation.php
│ │ │ ├── FakeMultiBindingConsumer.php
│ │ │ ├── FakeOnionInterceptor2.php
│ │ │ ├── FakeOnionInterceptor3.php
│ │ │ ├── FakeOnionInterceptor4.php
│ │ │ ├── FakeOpenCarModule.php
│ │ │ ├── FakeOverrideInstallModule.php
│ │ │ ├── FakePdoModule.php
│ │ │ ├── FakePhp8Car.php
│ │ │ ├── FakePhp8CarModule.php
│ │ │ ├── FakePhp8HandleProvider.php
│ │ │ ├── FakePriorityModule.php
│ │ │ ├── FakePropConstruct.php
│ │ │ ├── FakeRenameModule.php
│ │ │ ├── FakeRight.php
│ │ │ ├── FakeRightLeg.php
│ │ │ ├── FakeRobot.php
│ │ │ ├── FakeRobotInterface.php
│ │ │ ├── FakeRobotProvider.php
│ │ │ ├── FakeRobotTeam.php
│ │ │ ├── FakeSet.php
│ │ │ ├── FakeSetNotFoundWithMap.php
│ │ │ ├── FakeSetNotFoundWithProvider.php
│ │ │ ├── FakeToBindInvalidClassModule.php
│ │ │ ├── FakeToBindModule.php
│ │ │ ├── FakeToBindSingletonModule.php
│ │ │ ├── FakeToConstructorRobot.php
│ │ │ ├── FakeToProviderBindModule.php
│ │ │ ├── FakeToProviderSingletonBindModule.php
│ │ │ ├── FakeTyre.php
│ │ │ ├── FakeTyreInterface.php
│ │ │ ├── FakeUnNamedClass.php
│ │ │ ├── FakeUnNamedModule.php
│ │ │ ├── FakeUntarget.php
│ │ │ ├── FakeUntargetChild.php
│ │ │ ├── FakeUntargetModule.php
│ │ │ ├── FakeUntargetToIntanceModule.php
│ │ │ ├── FakeWalkRobot.php
│ │ │ ├── FakeWalkRobotLegProvider.php
│ │ │ ├── FakeWalkRobotModule.php
│ │ │ ├── FakelNoConstructorCallModule.php
│ │ │ └── NullVisitor.php
│ │ ├── GrapherTest.php
│ │ ├── InjectionPointTest.php
│ │ ├── InjectionPointsTest.php
│ │ ├── InjectorTest.php
│ │ ├── ModuleMergerTest.php
│ │ ├── ModuleTest.php
│ │ ├── MultiBinding/
│ │ │ ├── MultiBinderTest.php
│ │ │ └── MultiBindingModuleTest.php
│ │ ├── NameTest.php
│ │ ├── NewInstanceTest.php
│ │ ├── NoHintTest.php
│ │ ├── NullModuleTest.php
│ │ ├── ProviderProviderTest.php
│ │ ├── SetterMethodTest.php
│ │ ├── SetterMethodsTest.php
│ │ ├── SpyCompilerTest.php
│ │ ├── UnboundTest.php
│ │ ├── VisitorTest.php
│ │ └── script/
│ │ ├── aop.php
│ │ ├── bench.php
│ │ └── grapher.php
│ ├── script/
│ │ └── aop.php.cache
│ ├── stub/
│ │ └── BindInterface.phpstub
│ └── type/
│ └── InjectorInterfaceTest.php
├── tests-php8/
│ ├── AssistedInjectTest.php
│ └── DualReaderTest.php
└── vendor-bin/
└── tools/
└── composer.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
# Normalize line endings
* text=auto eol=lf
/tests export-ignore
/tests-php8 export-ignore
/demo export-ignore
/demo-php8 export-ignore
/.gitattributes export-ignore
/.github export-ignore
/vendor-bin export-ignore
/.gitignore export-ignore
/.scrutinizer.yml export-ignore
/.travis.yml export-ignore
/codecov.yml export-ignore
/phpcs.xml export-ignore
/phpmd.xml export-ignore
/phpstan.neon export-ignore
/phpunit.xml.dist export-ignore
/psalm.xml export-ignore
/psalm.compiler.xml export-ignore
# Configure diff output for .php and .phar files.
*.php diff=php
*.phar -diff
================================================
FILE: .github/CONTRIBUTING.md
================================================
# CONTRIBUTING
## Code Contributions
## Installation
Install project dependencies and test tools by running the following commands.
```bash
$ composer install
```
## Running tests
```bash
$ composer test
```
```bash
$ composer coverage // xdebug
$ composer pcov // pcov
```
Add tests for your new code ensuring that you have 100% code coverage.
In rare cases, code may be excluded from test coverage using `@codeCoverageIgnore`.
## Sending a pull request
To ensure your PHP code changes pass the CI checks, make sure to run all the same checks before submitting a PR.
```bash
$ composer tests
```
When you make a pull request, the tests will automatically be run again by GH action on multiple php versions.
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug Report
about: Create a bug report
labels: Bug
---
### Bug Report
<!-- Provide a summary describing the problem you are experiencing. -->
### How to reproduce
<!--- Describe exactly how to reproduce the problem, using a minimal test-case or working code sample. -->
================================================
FILE: .github/ISSUE_TEMPLATE/feature.md
================================================
---
name: Feature
about: Suggest a new feature or enhancement
labels: Feature
---
<!-- Write your suggestion here. -->
================================================
FILE: .github/ISSUE_TEMPLATE/question.md
================================================
---
name: Question
about: Ask a question regarding software usage
labels: Support
---
<!-- Write your question here. -->
================================================
FILE: .github/SECURITY.md
================================================
# Reporting a vulnerability
If you have found any issues that might have security implications,
please send a report privately to akihito.koriyama@gmail.com
Do not report security reports publicly.
================================================
FILE: .github/workflows/coding-standards.yml
================================================
name: Coding Standards
on:
push:
pull_request:
workflow_dispatch:
jobs:
cs:
uses: ray-di/.github/.github/workflows/coding-standards.yml@v1
with:
php_version: 8.3
================================================
FILE: .github/workflows/continuous-integration.yml
================================================
name: Continuous Integration
on:
push:
pull_request:
workflow_dispatch:
jobs:
ci:
uses: ray-di/.github/.github/workflows/continuous-integration.yml@v1
with:
old_stable: '["8.2", "8.3", "8.4"]'
current_stable: 8.5
script: demo/run.php
================================================
FILE: .github/workflows/demo.yml
================================================
name: Demo
on:
push:
pull_request:
workflow_dispatch:
jobs:
demo:
name: Demo
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.3
tools: cs2pr
coverage: none
- name: Get composer cache directory
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache dependencies
uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install dependencies
run: composer install --no-interaction --no-progress --prefer-dist
- name: Run Demo
run: php demo/run.php
================================================
FILE: .github/workflows/prefer-lowest.yml
================================================
name: Prefer Lowest
on:
push:
pull_request:
workflow_dispatch:
jobs:
prefer-lowest:
name: Prefer Lowest
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.2
tools: cs2pr
coverage: none
- name: Get composer cache directory
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache dependencies
uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install dependencies
run: composer update --prefer-lowest --no-interaction --no-progress --prefer-dist
- name: Run tests
run: composer test
================================================
FILE: .github/workflows/static-analysis.yml
================================================
name: Static Analysis
on:
push:
pull_request:
workflow_dispatch:
jobs:
sa:
uses: ray-di/.github/.github/workflows/static-analysis.yml@v1
with:
php_version: 8.3
================================================
FILE: .github/workflows/update-copyright-years-in-license-file.yml
================================================
name: Update copyright year(s) in license file
on:
workflow_dispatch:
schedule:
- cron: "0 3 1 1 *"
jobs:
run:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: FantasticFiasco/action-update-license-year@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
================================================
FILE: .gitignore
================================================
/vendor/
/build/
/tests/compiler/tmp/car/
/tests/compiler/tmp/injector_cache/
/tests/compiler/tmp/logger/
/tests/compiler/tmp/prod/
/tests/di/tmp/
/tests/di/script/grapher.php.txt
/tests/tmp/
/tests/compiler/tmp/
/*.cache.php
/.phpunit.result.cache
/composer.lock
/.phpcs-cache
/coverage.xml
/demo/error.log
/demo/10-cache.php.cache.php
/demo-php8/error.log
/demo-php8/10-cache.php.cache.php
/vendor-bin/**/vendor
================================================
FILE: .scrutinizer.yml
================================================
build:
image: default-jammy
environment:
php: 8.4
nodes:
analysis:
tests:
override:
- php-scrutinizer-run
filter:
paths: ["src/*"]
================================================
FILE: .sonarcloud.properties
================================================
# Exclude files from SonarCloud analysis
# - GitHub workflow files: version tags are best practice
# - Demo files: example code with intentional duplication for demonstration
sonar.exclusions=.github/workflows/**,demo/**
================================================
FILE: CLAUDE.md
================================================
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
Ray.Di is a dependency injection and AOP (Aspect-Oriented Programming) framework for PHP inspired by Google Guice. It provides annotations-based dependency injection with support for AOP interceptors.
## Core Architecture
### Key Components
- **AbstractModule**: Base class for defining dependency bindings. Modules are composed using `install()` and can be overridden using `override()`
- **Injector**: Main entry point that manages the DI container and creates instances. Auto-registers generated proxy classes and handles untargeted bindings
- **Bind**: Fluent API for creating bindings (`.to()`, `.toProvider()`, `.toInstance()`, `.in()`)
- **Container**: Internal storage for all bindings and dependencies
- **Annotations**: Located in `src/di/Di/` - includes `@Inject`, `@Named`, `@Assisted`, etc.
### Directory Structure
- `src/di/`: Core DI framework code
- `src-deprecated/`: Legacy code maintained for compatibility
- `tests/di/`: Unit tests with extensive fake classes for testing
- `demo/` and `demo-php8/`: Examples showing framework usage
- Compiled proxy classes are cached in configurable temp directories
## Development Commands
### Testing
```bash
composer test # Run PHPUnit tests
composer coverage # Generate test coverage with Xdebug
composer pcov # Generate coverage with PCOV (faster)
```
### Code Quality
```bash
composer cs # Run PHP_CodeSniffer
composer cs-fix # Auto-fix coding standards
composer sa # Static analysis (Psalm + PHPStan)
composer clean # Clear analysis caches
```
### Build Pipeline
```bash
composer build # Full build: cs + sa + pcov + metrics
composer tests # Quick check: cs + sa + test
```
### Analysis Tools
```bash
composer phpmd # PHP Mess Detector
composer metrics # Generate code metrics
composer baseline # Update static analysis baselines
```
## Testing Strategy
- Tests use extensive fake classes in `tests/di/Fake/` to simulate real-world scenarios
- Supports both PHP 7.2+ and PHP 8+ with separate test suites
- Cache files are automatically cleaned between test runs
- AOP proxy generation is tested with temporary directories
## Framework Patterns
### Module Definition
```php
class MyModule extends AbstractModule
{
protected function configure(): void
{
$this->bind(Interface::class)->to(Implementation::class);
$this->bind(Service::class)->toProvider(ServiceProvider::class);
}
}
```
### Injection Usage
```php
$injector = new Injector(new MyModule());
$instance = $injector->getInstance(Interface::class);
```
## Important Notes
- Ray.Di generates proxy classes for AOP which are cached in temp directories
- The framework supports both constructor and setter injection
- All bindings are resolved at runtime with automatic proxy weaving for aspects
- Multi-binding support allows collecting multiple implementations of the same interface
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2012-2026 Akihito Koriyama
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: README.md
================================================
# Ray.Di
## A dependency injection framework for PHP
[](https://scrutinizer-ci.com/g/ray-di/Ray.Di/?branch=2.x)
[](https://codecov.io/gh/ray-di/Ray.Di)
[](https://shepherd.dev/github/ray-di/Ray.Di)
[](https://github.com/ray-di/Ray.Di/actions/workflows/continuous-integration.yml)
[](https://packagist.org/packages/ray/di)
<img src="https://ray-di.github.io/images/logo.svg" width=160 alt="logo">
Ray.Di is DI and AOP framework for PHP inspired by [Google Guice](https://github.com/google/guice/wiki).
https://ray-di.github.io
================================================
FILE: codecov.yml
================================================
codecov:
notify:
require_ci_to_pass: yes
coverage:
status:
project:
default:
target: 100%
patch:
default:
target: 100%
================================================
FILE: composer-require-checker.json
================================================
{
"symbol-whitelist": [
"null", "true", "false",
"static", "self", "parent",
"array", "string", "int", "float", "bool", "iterable", "callable", "void", "object",
"Attribute", "ReflectionAttribute",
"Doctrine\\Common\\Cache\\CacheProvider"
]
}
================================================
FILE: composer.json
================================================
{
"name": "ray/di",
"description": "Guice style dependency injection framework",
"keywords": ["di", "aop"],
"license": "MIT",
"authors": [
{
"name": "Akihito Koriyama",
"email": "akihito.koriyama@gmail.com"
}
],
"require": {
"php": "^8.2",
"koriym/null-object": "^1.0",
"ray/aop": "^2.19"
},
"require-dev": {
"ext-pdo": "*",
"bamarni/composer-bin-plugin": "^1.4",
"infection/infection": "*",
"phpunit/phpunit": "^9.6.31"
},
"suggest": {
"ray/compiler": "For compiling dependency injection container to improve performance"
},
"config": {
"sort-packages": true,
"allow-plugins": {
"bamarni/composer-bin-plugin": true,
"infection/extension-installer": true
}
},
"autoload": {
"psr-4": {
"Ray\\Di\\": ["src/di", "src-deprecated/di"]
}
},
"autoload-dev": {
"psr-4": {
"Ray\\Di\\": ["tests/di", "tests/di/Fake/"]
}
},
"scripts": {
"test": "phpunit --log-junit=build/junit.xml",
"tests": ["@cs", "@sa", "@test"],
"coverage": ["php -dzend_extension=xdebug.so -dxdebug.mode=coverage ./vendor/bin/phpunit --coverage-text --coverage-html=build/coverage"],
"pcov": ["php -dextension=pcov.so -d pcov.enabled=1 ./vendor/bin/phpunit --coverage-text --coverage-html=build/coverage --coverage-xml=build/coverage-xml --coverage-clover=coverage.xml"],
"mutation": ["php -dextension=pcov.so -d pcov.enabled=1 vendor/bin/infection --coverage=build/coverage-xml --threads=2 --min-msi=80 --min-covered-msi=80 --no-progress"],
"cs": ["vendor-bin/tools/vendor/squizlabs/php_codesniffer/bin/phpcs --standard=./phpcs.xml src tests"],
"cs-fix": ["vendor-bin/tools/vendor/squizlabs/php_codesniffer/bin/phpcbf src tests"],
"clean": ["vendor-bin/tools/vendor/phpstan/phpstan/phpstan clear-result-cache", "vendor-bin/tools/vendor/vimeo/psalm/psalm --clear-cache", "rm -rf tests/tmp/*.php"],
"sa": ["vendor-bin/tools/vendor/vimeo/psalm/psalm -m -c psalm.xml --show-info=false", "vendor-bin/tools/vendor/phpstan/phpstan/phpstan analyse -c phpstan.neon --no-progress "],
"metrics": ["@test", "vendor-bin/tools/vendor/phpmetrics/phpmetrics/bin/phpmetrics --report-html=build/metrics --exclude=Exception --log-junit=build/junit.xml --junit=build/junit.xml src"],
"phpmd": ["vendor-bin/tools/vendor/phpmd/phpmd/src/bin/phpmd src/di text ./phpmd.xml"],
"build": ["@cs", "@sa", "@pcov", "@metrics"],
"baseline": ["vendor-bin/tools/vendor/phpstan/phpstan/phpstan analyse -c phpstan.neon --generate-baseline", "vendor-bin/tools/vendor/vimeo/psalm/psalm --set-baseline=psalm-baseline.xml"]
},
"extra": {
"bamarni-bin": {
"bin-links": true,
"forward-command": true
}
}
}
================================================
FILE: demo/01a-linked-binding.php
================================================
<?php
declare(strict_types=1);
use Ray\Di\AbstractModule;
use Ray\Di\Injector;
require dirname(__DIR__) . '/vendor/autoload.php';
interface FinderInterface
{
}
class Finder implements FinderInterface
{
}
interface MovieListerInterface
{
}
class MovieLister implements MovieListerInterface
{
public function __construct(
public FinderInterface $finder
){}
}
class FinderModule extends AbstractModule
{
protected function configure()
{
$this->bind(FinderInterface::class)->to(Finder::class);
$this->bind(MovieListerInterface::class)->to(MovieLister::class);
}
}
$injector = new Injector(new FinderModule());
$movieLister = $injector->getInstance(MovieListerInterface::class);
/** @var MovieLister $movieLister */
$works = ($movieLister->finder instanceof Finder);
echo($works ? 'It works!' : 'It DOES NOT work!') . PHP_EOL;
================================================
FILE: demo/01b-linked-binding-setter-injection.php
================================================
<?php
declare(strict_types=1);
use Ray\Di\AbstractModule;
use Ray\Di\Di\Inject;
use Ray\Di\Injector;
require dirname(__DIR__) . '/vendor/autoload.php';
interface FinderInterface
{
}
class Finder implements FinderInterface
{
}
interface MovieListerInterface
{
}
class MovieLister implements MovieListerInterface
{
public FinderInterface $finder;
#[Inject]
public function setFinder(FinderInterface $finder)
{
$this->finder = $finder;
}
}
class FinderModule extends AbstractModule
{
protected function configure()
{
$this->bind(FinderInterface::class)->to(Finder::class);
$this->bind(MovieListerInterface::class)->to(MovieLister::class);
}
}
$injector = new Injector(new FinderModule());
$movieLister = $injector->getInstance(MovieListerInterface::class);
/** @var MovieLister $movieLister */
$works = ($movieLister->finder instanceof Finder);
echo($works ? 'It works!' : 'It DOES NOT work!') . PHP_EOL;
================================================
FILE: demo/02-provider-binding.php
================================================
<?php
declare(strict_types=1);
use Ray\Di\AbstractModule;
use Ray\Di\Injector;
use Ray\Di\ProviderInterface;
require dirname(__DIR__) . '/vendor/autoload.php';
interface FinderInterface
{
}
class Finder implements FinderInterface
{
public $datetime;
public function __construct(DateTimeInterface $dateTime)
{
$this->datetime = $dateTime;
}
}
class FinderProvider implements ProviderInterface
{
/**
* {@inheritdoc}
*/
public function get()
{
return new Finder(new DateTimeImmutable('now'));
}
}
interface MovieListerInterface
{
}
class MovieLister implements MovieListerInterface
{
public function __construct(
public FinderInterface $finder
){
}
}
class FinderModule extends AbstractModule
{
protected function configure()
{
$this->bind(FinderInterface::class)->toProvider(FinderProvider::class);
$this->bind(MovieListerInterface::class)->to(MovieLister::class);
}
}
$injector = new Injector(new FinderModule());
$movieLister = $injector->getInstance(MovieListerInterface::class);
/** @var MovieLister $movieLister */
$works = ($movieLister->finder->datetime instanceof DateTimeImmutable);
echo($works ? 'It works!' : 'It DOES NOT work!') . PHP_EOL;
================================================
FILE: demo/02a-named-by-qualifier.php
================================================
<?php
declare(strict_types=1);
use Ray\Di\AbstractModule;
use Ray\Di\Di\Qualifier;
use Ray\Di\Injector;
require dirname(__DIR__) . '/vendor/autoload.php';
interface FinderInterface
{
}
class LegacyFinder implements FinderInterface
{
}
interface MovieListerInterface
{
}
class MovieLister implements MovieListerInterface
{
public FinderInterface $finder;
public function __construct(#[Legacy] FinderInterface $finder)
{
$this->finder = $finder;
}
}
#[Attribute(Attribute::TARGET_PARAMETER), Qualifier]
class Legacy
{
}
class FinderModule extends AbstractModule
{
protected function configure()
{
$this->bind(FinderInterface::class)->annotatedWith(Legacy::class)->to(LegacyFinder::class);
$this->bind(MovieListerInterface::class)->to(MovieLister::class);
}
}
$injector = new Injector(new FinderModule());
$movieLister = $injector->getInstance(MovieListerInterface::class);
/** @var MovieLister $movieLister */
$works = ($movieLister->finder instanceof LegacyFinder);
echo($works ? 'It works!' : 'It DOES NOT work!') . PHP_EOL;
================================================
FILE: demo/02b-named-by-named.php
================================================
<?php
declare(strict_types=1);
use Ray\Di\AbstractModule;
use Ray\Di\Di\Named;
use Ray\Di\Injector;
require dirname(__DIR__) . '/vendor/autoload.php';
interface FinderInterface
{
}
class LegacyFinder implements FinderInterface
{
}
class ModernFinder implements FinderInterface
{
}
interface MovieListerInterface
{
}
class MovieLister implements MovieListerInterface
{
public function __construct(
#[Named('legacy')] public FinderInterface $finder
){}
}
class FinderModule extends AbstractModule
{
protected function configure()
{
$this->bind(FinderInterface::class)->annotatedWith('legacy')->to(LegacyFinder::class);
$this->bind(MovieListerInterface::class)->to(MovieLister::class);
}
}
$injector = new Injector(new FinderModule());
$movieLister = $injector->getInstance(MovieListerInterface::class);
/** @var MovieLister $movieLister */
$works = ($movieLister->finder instanceof LegacyFinder);
echo($works ? 'It works!' : 'It DOES NOT work!') . PHP_EOL;
================================================
FILE: demo/03-injection-point.php
================================================
<?php
declare(strict_types=1);
use Ray\Di\AbstractModule;
use Ray\Di\InjectionPointInterface;
use Ray\Di\Injector;
use Ray\Di\ProviderInterface;
require dirname(__DIR__) . '/vendor/autoload.php';
interface FinderInterface
{
}
interface MovieListerInterface
{
}
class Finder implements FinderInterface
{
private string $className;
public function __construct(string $className)
{
$this->className = $className;
}
public function find(): string
{
return sprintf('search for [%s]', $this->className);
}
}
class MovieLister implements MovieListerInterface
{
public FinderInterface $finder;
public function __construct(FinderInterface $finder)
{
$this->finder = $finder;
}
}
class FinderProvider implements ProviderInterface
{
public function __construct(
public InjectionPointInterface $ip
)
{}
/**
* {@inheritdoc}
*/
public function get()
{
$className = $this->ip->getClass()->getName();
return new Finder($className);
}
}
class FinderModule extends AbstractModule
{
protected function configure()
{
$this->bind(FinderInterface::class)->toProvider(FinderProvider::class);
$this->bind(MovieListerInterface::class)->to(MovieLister::class);
}
}
$injector = new Injector(new FinderModule());
$movieLister = $injector->getInstance(MovieListerInterface::class);
/** @var MovieLister $movieLister */
$result = $movieLister->finder->find();
$works = ($result === 'search for [MovieLister]');
echo($works ? 'It works!' : 'It DOES NOT work!') . PHP_EOL;
================================================
FILE: demo/04-untarget-binding.php
================================================
<?php
declare(strict_types=1);
use Ray\Di\AbstractModule;
use Ray\Di\Injector;
use Ray\Di\Scope;
require dirname(__DIR__) . '/vendor/autoload.php';
class Finder
{
}
class FinderModule extends AbstractModule
{
protected function configure()
{
$this->bind(Finder::class)->in(Scope::SINGLETON);
}
}
$injector = new Injector(new FinderModule());
$finder1 = $injector->getInstance(Finder::class);
$finder2 = $injector->getInstance(Finder::class);
$works = spl_object_hash($finder1) === spl_object_hash($finder2);
echo($works ? 'It works!' : 'It DOES NOT work!') . PHP_EOL;
================================================
FILE: demo/05a-constructor-binding.php
================================================
<?php
declare(strict_types=1);
require dirname(__DIR__) . '/vendor/autoload.php';
use Ray\Di\AbstractModule;
use Ray\Di\Injector;
// public PDO::__construct ( string $dsn [, string $username [, string $password [, array $options ]]] )
class PdoModuleLegacyNaming extends AbstractModule
{
protected function configure()
{
// 'dsn=pdo_dsn' (still) works
$this->bind(PDO::class)->toConstructor(PDO::class, 'dsn=pdo_dsn');
$this->bind()->annotatedWith('pdo_dsn')->toInstance('sqlite::memory:');
}
}
class PdoModule extends AbstractModule
{
protected function configure()
{
// ['dsn' => 'pdo_dsn'] works (recommended)
$this->bind(PDO::class)->toConstructor(PDO::class, ['dsn' => 'pdo_dsn']);
$this->bind()->annotatedWith('pdo_dsn')->toInstance('sqlite::memory:');
}
}
$injector = new Injector(new PdoModuleLegacyNaming());
$pdo = $injector->getInstance(PDO::class);
$works = $pdo instanceof PDO;
$injector = new Injector(new PdoModule());
$pdo = $injector->getInstance(PDO::class);
$works &= $pdo instanceof PDO;
echo($works ? 'It works!' : 'It DOES NOT work!') . PHP_EOL;
================================================
FILE: demo/05b-constructor-binding-setter-injection.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Demo;
use Ray\Di\AbstractModule;
use Ray\Di\InjectionPoints;
use Ray\Di\Injector;
use function dirname;
use const PHP_EOL;
require dirname(__DIR__) . '/vendor/autoload.php';
interface FinderInterface
{
}
interface MovieListerInterface
{
}
class Finder implements FinderInterface
{
}
class MovieLister implements MovieListerInterface
{
public FinderInterface $finder;
/**
* Setter Injection with no Inject annotation
*/
public function setFinder(FinderInterface $finder)
{
$this->finder = $finder;
}
}
class ListerModule extends AbstractModule
{
protected function configure()
{
$this->bind(FinderInterface::class)->to(Finder::class);
$this->bind(MovieListerInterface::class)->toConstructor(
MovieLister::class,
'',
(new InjectionPoints())->addMethod('setFinder') // or (new InjectionPoints)->addOptionalMethod('setFinder')
);
}
}
$injector = new Injector(new ListerModule());
$lister = $injector->getInstance(MovieListerInterface::class);
/** @var MovieLister $lister */
$works = ($lister->finder instanceof FinderInterface);
echo($works ? 'It works!' : 'It DOES NOT work!') . PHP_EOL;
================================================
FILE: demo/07-assisted-injection.php
================================================
<?php
declare(strict_types=1);
use Composer\Autoload\ClassLoader;
use Ray\Di\AbstractModule;
use Ray\Di\Injector;
$loader = require dirname(__DIR__) . '/vendor/autoload.php';
/** @var ClassLoader $loader */
$loader->addPsr4('', __DIR__ . '/finder');
$injector = new Injector(new class extends AbstractModule{
protected function configure()
{
$this->bind(FinderInterface::class)->to(Finder::class);
}
});
$finder = $injector->getInstance(MovieFinder::class);
/** @var MovieFinder $finder */
$works = $finder->find('Tokyo Story') === 'searching [Tokyo Story] by [Finder]';
echo($works ? 'It works!' : 'It DOES NOT work!') . PHP_EOL;
================================================
FILE: demo/10-cache.php
================================================
<?php
declare(strict_types=1);
use Composer\Autoload\ClassLoader;
use Ray\Di\Injector;
$loader = require dirname(__DIR__) . '/vendor/autoload.php';
/** @var ClassLoader $loader */
$loader->addPsr4('', __DIR__ . '/finder');
$start = microtime(true);
$injector = new Injector(new FinderModule());
$movieLister = $injector->getInstance(MovieListerInterface::class);
assert($movieLister instanceof MovieLister);
$time1 = microtime(true) - $start;
// save file cache
file_put_contents(__FILE__ . '.cache.php', serialize(new Injector(new FinderModule())));
// cached injector
$start = microtime(true);
$injector = unserialize(file_get_contents(__FILE__ . '.cache.php'));
$movieLister2 = $injector->getInstance(MovieListerInterface::class);
assert($movieLister2 instanceof MovieLister);
$time2 = microtime(true) - $start;
$works = $movieLister instanceof MovieListerInterface;
echo $works ? 'It works!' : 'It DOES NOT work!';
echo ' [Injector cache] x' . round($time1 / $time2) . ' times faster.' . PHP_EOL;
================================================
FILE: demo/11-script-injector.php
================================================
<?php
declare(strict_types=1);
use Composer\Autoload\ClassLoader;
use Ray\Compiler\DiCompiler;
use Ray\Compiler\ScriptInjector;
use Ray\Di\Injector;
$loader = require dirname(__DIR__) . '/vendor/autoload.php';
/** @var ClassLoader $loader */
$loader->addPsr4('', __DIR__ . '/finder');
$start = microtime(true);
$injector = new Injector(new FinderModule());
$movieLister = $injector->getInstance(MovieListerInterface::class);
assert($movieLister instanceof MovieLister);
$time1 = microtime(true) - $start;
// compile
$tmpDir = __DIR__ . '/tmp';
$compiler = new DiCompiler(new FinderModule(), $tmpDir);
$compiler->compile();
$scriptInjector = new ScriptInjector($tmpDir);
$movieLister2 = $scriptInjector->getInstance(MovieListerInterface::class);
// script injector
$start = microtime(true);
$movieLister2 = $scriptInjector->getInstance(MovieListerInterface::class);
assert($movieLister2 instanceof MovieLister);
$time2 = microtime(true) - $start;
$works = $movieLister instanceof MovieListerInterface;
echo $works ? 'It works!' : 'It DOES NOT work!';
echo ' [Script injector] x' . round($time1 / $time2) . ' times faster.' . PHP_EOL;
================================================
FILE: demo/12-dependency-chain-error-message.php
================================================
<?php
declare(strict_types=1);
use Composer\Autoload\ClassLoader;
use Ray\Di\AbstractModule;
use Ray\Di\Exception\Unbound;
use Ray\Di\Injector;
$loader = require dirname(__DIR__) . '/vendor/autoload.php';
/** @var ClassLoader $loader */
$loader->addPsr4('', __DIR__ . '/chain-error');
class DeepLinkedClassBindingModule extends AbstractModule
{
protected function configure()
{
$this->bind(A::class);
$this->bind(B::class);
$this->bind(C::class);
$this->bind(D::class);
// purposefully not bound.
// D will require EInterface object to be injected, but
// EInterface is not bound and an Unbound exception is thrown.
}
}
$injector = new Injector(new DeepLinkedClassBindingModule());
// this will fail with an exception as EInterface is not bound
try {
$injector->getInstance(A::class);
} catch (Unbound $e) {
$msg = $e->getMessage();
ob_start();
// dependency 'B' with name '' used
// dependency 'B' with name '' used in12-dependency-chain-error-message.php:11
echo PHP_EOL . '---------' . PHP_EOL;
echo $e;
// exception 'Ray\Di\Exception\Unbound' with message 'EInterface-'
// - dependency 'EInterface' with name '' used in12-dependency-chain-error-message.php:26
// - dependency 'D' with name '' used in12-dependency-chain-error-message.php:21
// - dependency 'C' with name '' used in12-dependency-chain-error-message.php:16
// - dependency 'B' with name '' used in12-dependency-chain-error-message.php:11
// ...
echo PHP_EOL . '---------' . PHP_EOL;
do {
echo get_class($e) . ':' . $e->getMessage() . PHP_EOL;
} while ($e = $e->getPrevious());
// Ray\Di\Exception\Unbound:dependency 'B' with name '' used in12-dependency-chain-error-message.php:11
// Ray\Di\Exception\Unbound:dependency 'C' with name '' used in12-dependency-chain-error-message.php:16
// Ray\Di\Exception\Unbound:dependency 'D' with name '' used in12-dependency-chain-error-message.php:21
// Ray\Di\Exception\Unbound:dependency 'EInterface' with name '' used in12-dependency-chain-error-message.php:26
// Ray\Di\Exception\Unbound:EInterface-
}
$log = ob_get_clean();
$works = strpos($log, "dependency 'B' with name '' used");
echo $works ? 'It works!' : 'It DOES NOT work!';
file_put_contents(__DIR__ . '/error.log', $log);
echo '[error log]: ' . __DIR__ . '/error.log' . PHP_EOL;
================================================
FILE: demo/chain-error/A.php
================================================
<?php
declare(strict_types=1);
class A
{
public function __construct(B $b)
{
}
}
================================================
FILE: demo/chain-error/B.php
================================================
<?php
declare(strict_types=1);
class B
{
public function __construct(C $c)
{
}
}
================================================
FILE: demo/chain-error/C.php
================================================
<?php
declare(strict_types=1);
class C
{
public function __construct(D $d)
{
}
}
================================================
FILE: demo/chain-error/D.php
================================================
<?php
declare(strict_types=1);
class D
{
public function __construct(EInterface $e)
{
}
}
================================================
FILE: demo/chain-error/EInterface.php
================================================
<?php
declare(strict_types=1);
interface EInterface
{
}
================================================
FILE: demo/finder/Db.php
================================================
<?php
declare(strict_types=1);
use Ray\Di\Di\PostConstruct;
class Db implements DbInterface
{
public function __construct($dsn, $username, $password)
{
}
#[PostConstruct]
public function init()
{
}
}
================================================
FILE: demo/finder/DbFinder.php
================================================
<?php
declare(strict_types=1);
use Ray\Di\Di\Inject;
class DbFinder implements FinderInterface
{
public function __construct(DbInterface $db)
{
}
#[Inject]
public function setDb(DbInterface $db)
{
}
#[Inject]
public function setSorter(Sorter $sorter, Sorter $sorte2)
{
}
}
================================================
FILE: demo/finder/DbInterface.php
================================================
<?php
declare(strict_types=1);
interface DbInterface
{
}
================================================
FILE: demo/finder/Finder.php
================================================
<?php
declare(strict_types=1);
class Finder implements FinderInterface
{
}
================================================
FILE: demo/finder/FinderInterface.php
================================================
<?php
declare(strict_types=1);
interface FinderInterface
{
}
================================================
FILE: demo/finder/FinderModule.php
================================================
<?php
declare(strict_types=1);
use Ray\Di\AbstractModule;
use Ray\Di\Scope;
class FinderModule extends AbstractModule
{
protected function configure()
{
$this->bind(Sorter::class)->in(Scope::SINGLETON);
$this->bind(DbInterface::class)->toConstructor(Db::class, 'dsn=dsn,username=username,password=password');
$this->bind()->annotatedWith('dsn')->toInstance('msql:host=localhost;dbname=test');
$this->bind()->annotatedWith('username')->toInstance('root');
$this->bind()->annotatedWith('password')->toInstance('');
$this->bind(FinderInterface::class)->to(DbFinder::class);
$this->bind(MovieListerInterface::class)->to(MovieLister::class);
}
}
================================================
FILE: demo/finder/MovieFinder.php
================================================
<?php
declare(strict_types=1);
use Ray\Di\Di\Assisted;
use Ray\Di\Di\Inject;
class MovieFinder
{
public function find($name, #[Inject] ?FinderInterface $finder = null)
{
return sprintf('searching [%s] by [%s]', $name, get_class($finder));
}
}
================================================
FILE: demo/finder/MovieLister.php
================================================
<?php
declare(strict_types=1);
use Ray\Di\Di\Inject;
class MovieLister implements MovieListerInterface
{
public function __construct(FinderInterface $finder)
{
}
#[Inject]
public function setFinder01(FinderInterface $finder, FinderInterface $finder1, FinderInterface $finder2)
{
}
}
================================================
FILE: demo/finder/MovieListerInterface.php
================================================
<?php
declare(strict_types=1);
interface MovieListerInterface
{
}
================================================
FILE: demo/finder/Sorter.php
================================================
<?php
declare(strict_types=1);
class Sorter
{
}
================================================
FILE: demo/run.php
================================================
<?php
declare(strict_types=1);
putenv('TMPDIR=' . __DIR__ . '/tmp');
passthru('php ' . __DIR__ . '/01a-linked-binding.php');
passthru('php ' . __DIR__ . '/01b-linked-binding-setter-injection.php');
passthru('php ' . __DIR__ . '/02-provider-binding.php');
passthru('php ' . __DIR__ . '/02a-named-by-qualifier.php');
passthru('php ' . __DIR__ . '/02b-named-by-named.php');
passthru('php ' . __DIR__ . '/03-injection-point.php');
passthru('php ' . __DIR__ . '/04-untarget-binding.php');
passthru('php ' . __DIR__ . '/05a-constructor-binding.php');
passthru('php ' . __DIR__ . '/05b-constructor-binding-setter-injection.php');
passthru('php ' . __DIR__ . '/07-assisted-injection.php');
passthru('php ' . __DIR__ . '/10-cache.php');
passthru('php ' . __DIR__ . '/11-script-injector.php');
passthru('php ' . __DIR__ . '/12-dependency-chain-error-message.php');
================================================
FILE: demo/tmp/.gitkeep
================================================
================================================
FILE: phpcs.xml
================================================
<?xml version="1.0"?>
<ruleset
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="bearcs"
xsi:noNamespaceSchemaLocation="./vendor-bin/tools/vendor/squizlabs/php_codesniffer/phpcs.xsd">
<arg name="basepath" value="."/>
<arg name="extensions" value="php"/>
<arg name="parallel" value="80"/>
<arg name="cache" value=".phpcs-cache"/>
<!-- Compatibility with PHP 7.2.0 -->
<config name="php_version" value="70200"/>
<!-- Ignore warnings, show progress of the run and show sniff names -->
<arg value="nps"/>
<!-- Directories to be checked -->
<file>src</file>
<file>tests</file>
<exclude-pattern>*/tests/tmp/*</exclude-pattern>
<!-- PSR12 Coding Standard -->
<rule ref="PSR12"/>
<!-- Doctrine Coding Standard -->
<rule ref="Doctrine">
<!-- Inapplicable for this project -->
<!-- Base -->
<exclude name="Generic.Formatting.MultipleStatementAlignment.NotSame"/>
<exclude name="Squiz.Strings.DoubleQuoteUsage.ContainsVar"/>
<exclude name="Squiz.WhiteSpace.LanguageConstructSpacing"/>
<exclude name="SlevomatCodingStandard.Classes.SuperfluousAbstractClassNaming.SuperfluousPrefix"/>
<exclude name="SlevomatCodingStandard.Classes.SuperfluousExceptionNaming.SuperfluousSuffix"/>
<exclude name="SlevomatCodingStandard.Classes.SuperfluousInterfaceNaming.SuperfluousSuffix"/>
<exclude name="SlevomatCodingStandard.Commenting.InlineDocCommentDeclaration.MissingVariable"/>
<exclude name="SlevomatCodingStandard.Commenting.UselessInheritDocComment.UselessInheritDocComment"/>
<exclude name="SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint"/>
<exclude name="SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint"/>
<exclude name="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingNativeTypeHint"/>
<exclude name="Squiz.PHP.GlobalKeyword.NotAllowed"/>
<exclude name="SlevomatCodingStandard.PHP.RequireExplicitAssertion.RequiredExplicitAssertion"/>
<exclude name="SlevomatCodingStandard.Commenting.InlineDocCommentDeclaration.InvalidFormat"/>
<exclude name="Squiz.Commenting.FunctionComment.InvalidNoReturn"/>
<!-- PHP8 attribute -->
<exclude name="PSR12.Files.FileHeader.IncorrectOrder"/>
<!-- /Base -->
<!-- Option -->
<exclude name="SlevomatCodingStandard.ControlStructures.EarlyExit.EarlyExitNotUsed"/>
<!-- /Option -->
<!-- exclude for PHP8 attributes -->
<exclude name="PEAR.Commenting.InlineComment.WrongStyle" />
<exclude name="PSR12.Files.FileHeader.SpacingAfterBlock" />
<!-- Exclude Fake files form Doctrine CS -->
<exclude-pattern>*/tests/Fake/*</exclude-pattern>
</rule>
<!-- Additional Rules -->
<rule ref="Generic.WhiteSpace.LanguageConstructSpacing"/>
<rule ref="SlevomatCodingStandard.Namespaces.UnusedUses">
<properties>
<property name="searchAnnotations" value="true"/>
</properties>
</rule>
<rule ref="SlevomatCodingStandard.Commenting.DocCommentSpacing">
<properties>
<property name="annotationsGroups" type="array">
<element value="@param, @psalm-param, @phpstan-param"/>
<element value="@return, @psalm-return, @phpstan-return"/>
<element value="@throws"/>
</property>
</properties>
</rule>
<rule ref="SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint">
<include-pattern>src/Module/*</include-pattern>
<include-pattern>tests/*</include-pattern>
</rule>
<rule ref="SlevomatCodingStandard.Classes.PropertySpacing">
<properties>
<property name="minLinesCountBeforeWithComment" value="1"/>
<property name="maxLinesCountBeforeWithComment" value="1"/>
<property name="maxLinesCountBeforeWithoutComment" value="0"/>
</properties>
</rule>
<exclude-pattern>*/Fake/*</exclude-pattern>
<exclude-pattern>*/tmp/*</exclude-pattern>
</ruleset>
================================================
FILE: phpmd.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<ruleset name="PHPMD rule set"
xmlns="http://pmd.sf.net/ruleset/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
<!--codesize-->
<rule ref="rulesets/codesize.xml/CyclomaticComplexity"/>
<rule ref="rulesets/codesize.xml/NPathComplexity"/>
<rule ref="rulesets/codesize.xml/ExcessiveClassComplexity"/>
<rule ref="rulesets/codesize.xml/ExcessiveClassLength"/>
<rule ref="rulesets/codesize.xml/ExcessiveMethodLength"/>
<rule ref="rulesets/codesize.xml/ExcessiveParameterList"/>
<rule ref="rulesets/codesize.xml/ExcessivePublicCount"/>
<rule ref="rulesets/codesize.xml/TooManyFields"/>
<rule ref="rulesets/codesize.xml/TooManyMethods"/>
<!--design-->
<rule ref="rulesets/design.xml/EvalExpression"/>
<rule ref="rulesets/design.xml/ExitExpression"/>
<rule ref="rulesets/design.xml/GotoStatement" />
<rule ref="rulesets/design.xml/NumberOfChildren"/>
<rule ref="rulesets/design.xml/DepthOfInheritance"/>
<!-- <rule ref="rulesets/design.xml/CouplingBetweenObjects" /> -->
<!--naming-->
<rule ref="rulesets/naming.xml/ConstantNamingConventions"/>
<rule ref="rulesets/naming.xml/BooleanGetMethodName"/>
<!--unusedcode-->
<rule ref="rulesets/unusedcode.xml/UnusedFormalParameter"/>
<rule ref="rulesets/unusedcode.xml/UnusedLocalVariable"/>
<rule ref="rulesets/unusedcode.xml/UnusedPrivateField"/>
<rule ref="rulesets/unusedcode.xml/UnusedPrivateMethod"/>
<!--controversial-->
<rule ref="rulesets/controversial.xml/CamelCaseClassName"/>
<rule ref="rulesets/controversial.xml/CamelCasePropertyName"/>
<rule ref="rulesets/controversial.xml/CamelCaseMethodName"/>
<!--cleancode-->
<rule ref="rulesets/cleancode.xml/BooleanArgumentFlag"/>
<rule ref="rulesets/cleancode.xml/ElseExpression" />
</ruleset>
================================================
FILE: phpstan.neon
================================================
parameters:
errorFormat: raw
level: max
paths:
- src/di
- tests/di
- tests/type
excludePaths:
- tests/tmp/*
- tests/di/tmp/*
- tests/Di/tmp/*
- tests/di/Fake/*
- tests/di/Ray_Di_*
- tests/di/script/*
ignoreErrors:
- '#contains generic class ReflectionAttribute but does not specify its types:#'
- '#generic class ReflectionAttribute but does not specify its types:#'
================================================
FILE: phpunit.xml.dist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
bootstrap="tests/bootstrap.php"
convertDeprecationsToExceptions="true"
>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">src/di</directory>
</include>
</coverage>
<testsuites>
<testsuite name="Ray.Di Test Suite">
<directory>tests/di/</directory>
<directory phpVersion="8.0.0" phpVersionOperator=">=">tests-php8</directory>
<directory>tests/di</directory>
</testsuite>
</testsuites>
<php>
<ini name="error_reporting" value="-1"/>
</php>
</phpunit>
================================================
FILE: psalm.xml
================================================
<?xml version="1.0"?>
<psalm
errorLevel="1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config https://psalm.dev/schema/config"
findUnusedCode="false"
>
<projectFiles>
<directory name="src/di"/>
</projectFiles>
<stubs>
<file name="tests/stub/BindInterface.phpstub"/>
</stubs>
<issueHandlers>
<MissingOverrideAttribute errorLevel="suppress"/>
</issueHandlers>
</psalm>
================================================
FILE: rector.php
================================================
<?php
declare(strict_types=1);
use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\LevelSetList;
use Rector\Set\ValueObject\SetList;
return RectorConfig::configure()
->withPaths([
__DIR__ . '/src/di',
])
->withSkip([
__DIR__ . '/src-deprecated',
])
->withPhpSets(php82: true)
->withPreparedSets(
deadCode: true,
codeQuality: true,
codingStyle: true,
typeDeclarations: true,
privatization: true,
instanceOf: true,
earlyReturn: true
);
================================================
FILE: src/di/AbstractModule.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Aop\AbstractMatcher;
use Ray\Aop\Matcher;
use Ray\Aop\Pointcut;
use Ray\Aop\PriorityPointcut;
use Stringable;
use function assert;
use function class_exists;
use function interface_exists;
/**
* @psalm-import-type BindableInterface from Types
* @psalm-import-type PointcutList from Types
* @psalm-import-type InterceptorClassList from Types
*/
abstract class AbstractModule implements Stringable
{
/** @var Matcher */
protected $matcher;
/** @var ?AbstractModule */
protected $lastModule;
private ?Container $container = null;
public function __construct(
?self $module = null
) {
$this->lastModule = $module;
$this->activate();
if ($module instanceof self && $this->container instanceof Container) {
$this->container->merge($module->getContainer());
}
}
public function __toString(): string
{
return (new ModuleString())($this->getContainer(), $this->getContainer()->getPointcuts());
}
/**
* Install module
*/
public function install(self $module): void
{
$this->getContainer()->merge($module->getContainer());
}
/**
* Override module
*/
public function override(self $module): void
{
$module->getContainer()->merge($this->getContainer());
$this->container = $module->getContainer();
}
/**
* Return activated container
*/
public function getContainer(): Container
{
if ($this->container === null) {
$this->activate();
}
assert($this->container instanceof Container);
return $this->container;
}
/**
* Bind interceptor
*
* @param InterceptorClassList $interceptors
*/
public function bindInterceptor(AbstractMatcher $classMatcher, AbstractMatcher $methodMatcher, array $interceptors): void
{
$pointcut = new Pointcut($classMatcher, $methodMatcher, $interceptors);
$this->getContainer()->addPointcut($pointcut);
foreach ($interceptors as $interceptor) {
if (class_exists($interceptor)) {
(new Bind($this->getContainer(), $interceptor))->to($interceptor)->in(Scope::SINGLETON);
return;
}
assert(interface_exists($interceptor));
(new Bind($this->getContainer(), $interceptor))->in(Scope::SINGLETON);
}
}
/**
* Bind interceptor early
*
* @param InterceptorClassList $interceptors
*/
public function bindPriorityInterceptor(AbstractMatcher $classMatcher, AbstractMatcher $methodMatcher, array $interceptors): void
{
$pointcut = new PriorityPointcut($classMatcher, $methodMatcher, $interceptors);
$this->getContainer()->addPointcut($pointcut);
foreach ($interceptors as $interceptor) {
(new Bind($this->getContainer(), $interceptor))->to($interceptor)->in(Scope::SINGLETON);
}
}
/**
* Rename binding name
*
* @param string $interface Interface
* @param string $newName New binding name
* @param string $sourceName Original binding name
* @param string $targetInterface Original interface
*/
public function rename(string $interface, string $newName, string $sourceName = Name::ANY, string $targetInterface = ''): void
{
$targetInterface = $targetInterface ?: $interface;
if ($this->lastModule instanceof self) {
$this->lastModule->getContainer()->move($interface, $sourceName, $targetInterface, $newName);
}
}
/**
* Configure binding
*
* @return void
*
* @noinspection ReturnTypeCanBeDeclaredInspection
*/
abstract protected function configure();
/**
* Bind interface
*
* @param BindableInterface $interface
*/
protected function bind(string $interface = ''): Bind
{
return new Bind($this->getContainer(), $interface);
}
/**
* Activate bindings
*/
private function activate(): void
{
$this->container = new Container();
$this->matcher = new Matcher();
$this->configure();
}
}
================================================
FILE: src/di/AcceptInterface.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
/**
* This interface defines the accept method, which allows an object to accept a visitor.
*/
interface AcceptInterface
{
/**
* Accepts a visitor and applies its behavior on the current object.
*
* @param VisitorInterface $visitor The visitor to accept
*
* @return mixed|void
*/
public function accept(VisitorInterface $visitor);
}
================================================
FILE: src/di/AnnotatedClass.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Aop\ReflectionClass;
use Ray\Di\Di\PostConstruct;
use ReflectionMethod;
final class AnnotatedClass
{
private AnnotatedClassMethods $injectionMethod;
public function __construct()
{
$this->injectionMethod = new AnnotatedClassMethods();
}
/**
* Return factory instance
*
* @phpstan-param ReflectionClass<object> $class Target class reflection
*/
public function getNewInstance(ReflectionClass $class): NewInstance
{
$setterMethods = new SetterMethods([]);
$methods = $class->getMethods();
foreach ($methods as $method) {
if ($method->name === '__construct') {
continue;
}
$setterMethods->add($this->injectionMethod->getSetterMethod($method));
}
$name = $this->injectionMethod->getConstructorName($class);
return new NewInstance($class, $setterMethods, $name);
}
/**
* Return @-PostConstruct method reflection
*
* @phpstan-param ReflectionClass<object> $class
*/
public function getPostConstruct(ReflectionClass $class): ?ReflectionMethod
{
$methods = $class->getMethods();
foreach ($methods as $method) {
$annotation = $method->getAnnotation(PostConstruct::class);
if ($annotation instanceof PostConstruct) {
return $method;
}
}
return null;
}
}
================================================
FILE: src/di/AnnotatedClassMethods.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Aop\ReflectionClass;
use Ray\Aop\ReflectionMethod;
use Ray\Di\Di\InjectInterface;
use ReflectionAttribute;
final class AnnotatedClassMethods
{
/**
* @phpstan-param ReflectionClass<object> $class
*/
public function getConstructorName(ReflectionClass $class): Name
{
$constructor = $class->getConstructor();
if (! $constructor instanceof \ReflectionMethod) {
return new Name(Name::ANY);
}
$reflMethod = new \ReflectionMethod($class->getName(), '__construct');
$name = Name::withAttributes($reflMethod);
if ($name instanceof Name) {
return $name;
}
return new Name(Name::ANY);
}
public function getSetterMethod(ReflectionMethod $method): ?SetterMethod
{
$inject = $method->getAnnotation(InjectInterface::class, ReflectionAttribute::IS_INSTANCEOF);
if (! $inject instanceof InjectInterface) {
return null;
}
$name = $this->getName($method);
$setterMethod = new SetterMethod($method, $name);
if ($inject->isOptional()) {
$setterMethod->setOptional();
}
return $setterMethod;
}
private function getName(ReflectionMethod $method): Name
{
$name = Name::withAttributes($method);
if ($name instanceof Name) {
return $name;
}
return new Name(Name::ANY);
}
}
================================================
FILE: src/di/Annotation/ScriptDir.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Annotation;
use Attribute;
use Ray\Di\Di\Qualifier;
/**
* Script directory
*
* This qualifier should not use in an application code.
*/
#[Attribute, Qualifier]
final class ScriptDir
{
}
================================================
FILE: src/di/Argument.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use ReflectionException;
use ReflectionMethod;
use ReflectionNamedType;
use ReflectionParameter;
use Stringable;
use function assert;
use function in_array;
use function sprintf;
/**
* @psalm-import-type DependencyIndex from Types
*/
final class Argument implements AcceptInterface, Stringable
{
public const UNBOUND_TYPE = ['bool', 'int', 'float', 'string', 'array', 'resource', 'callable', 'iterable'];
/** @var DependencyIndex */
private string $index;
private bool $isDefaultAvailable;
/** @var mixed */
private $default;
private string $meta;
private ReflectionParameter $reflection;
public function __construct(ReflectionParameter $parameter, string $name)
{
$type = $this->getType($parameter);
$isOptional = $parameter->isOptional();
$this->isDefaultAvailable = $parameter->isDefaultValueAvailable() || $isOptional;
if ($isOptional) {
$this->default = null;
}
$this->setDefaultValue($parameter);
$this->index = $type . '-' . $name;
$this->reflection = $parameter;
$this->meta = sprintf(
"'%s-%s' in %s:%d ($%s)",
$type,
$name,
$this->reflection->getDeclaringFunction()->getFileName(),
$this->reflection->getDeclaringFunction()->getStartLine(),
$parameter->getName()
);
}
/**
* Return index
*
* @return DependencyIndex
*/
public function __toString(): string
{
return $this->index;
}
/**
* Return reflection
*/
public function get(): ReflectionParameter
{
return $this->reflection;
}
public function isDefaultAvailable(): bool
{
return $this->isDefaultAvailable;
}
/**
* @return mixed
*/
public function getDefaultValue()
{
return $this->default;
}
public function getMeta(): string
{
return $this->meta;
}
/**
* @return array<mixed>
*/
public function __serialize(): array
{
$method = $this->reflection->getDeclaringFunction();
assert($method instanceof ReflectionMethod);
$ref = [
$method->class,
$method->name,
$this->reflection->getName(),
];
return [
$this->index,
$this->isDefaultAvailable,
$this->default,
$this->meta,
$ref,
];
}
/**
* @param array{0: DependencyIndex, 1: bool, 2: string, 3: string, 4: string, 5: array{0: string, 1: string, 2:string}} $unserialized
*/
public function __unserialize(array $unserialized): void
{
[
$this->index,
$this->isDefaultAvailable,
$this->default,
$this->meta,
$ref,
] = $unserialized;
$this->reflection = new ReflectionParameter([$ref[0], $ref[1]], $ref[2]);
}
/** @inheritDoc */
public function accept(VisitorInterface $visitor): void
{
$visitor->visitArgument(
$this->index,
$this->isDefaultAvailable,
$this->default,
$this->reflection
);
}
private function setDefaultValue(ReflectionParameter $parameter): void
{
if (! $this->isDefaultAvailable) {
return;
}
try {
$this->default = $parameter->getDefaultValue();
// @codeCoverageIgnoreStart
} catch (ReflectionException) {
$this->default = null;
// @codeCoverageIgnoreEnd
}
}
/**
* @psalm-pure
*/
private function getType(ReflectionParameter $parameter): string
{
$type = $parameter->getType();
return $type instanceof ReflectionNamedType && ! in_array($type->getName(), self::UNBOUND_TYPE, true) ? $type->getName() : '';
}
}
================================================
FILE: src/di/Arguments.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Di\Exception\NoHint;
use Ray\Di\Exception\Unbound;
use ReflectionMethod;
use function sprintf;
/**
* @psalm-import-type ArgumentsList from Types
* @psalm-import-type MethodArguments from Types
*/
final class Arguments implements AcceptInterface
{
/** @var ArgumentsList */
private array $arguments = [];
public function __construct(ReflectionMethod $method, Name $name)
{
$parameters = $method->getParameters();
foreach ($parameters as $parameter) {
$this->arguments[] = new Argument($parameter, $name($parameter));
}
}
/**
* Return arguments
*
* @return list<mixed>
*
* @throws Exception\Unbound
*/
public function inject(Container $container): array
{
$parameters = [];
foreach ($this->arguments as $parameter) {
/** @psalm-suppress MixedAssignment */
$parameters[] = $this->getParameter($container, $parameter);
}
return $parameters;
}
public function accept(VisitorInterface $visitor): void
{
$visitor->visitArguments($this->arguments);
}
/**
* @return mixed
*
* @throws Unbound
*/
private function getParameter(Container $container, Argument $argument)
{
$this->bindInjectionPoint($container, $argument);
try {
return $container->getDependency((string) $argument);
} catch (Unbound $unbound) {
if ($argument->isDefaultAvailable()) {
return $argument->getDefaultValue();
}
if ($unbound instanceof NoHint) {
throw new NoHint($this->getNoHintMsg($argument), 0, $unbound);
}
throw new Unbound($argument->getMeta(), 0, $unbound);
}
}
private function bindInjectionPoint(Container $container, Argument $argument): void
{
$isSelf = (string) $argument === InjectionPointInterface::class . '-' . Name::ANY;
if ($isSelf) {
return;
}
(new Bind($container, InjectionPointInterface::class))->toInstance(new InjectionPoint($argument->get()));
}
private function getNoHintMsg(Argument $argument): string
{
$ref = $argument->get();
$func = $ref->getDeclaringFunction();
$fileName = $func->getFileName();
return sprintf(
'$%s (%s:%d)',
$ref->getName(),
$fileName !== false ? $fileName : 'unknown file',
$func->getStartLine()
);
}
}
================================================
FILE: src/di/AspectBind.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Aop\Bind as AopBind;
use Ray\Aop\MethodInterceptor;
use function assert;
/**
* @psalm-import-type MethodInterceptorBindings from Types
*/
final class AspectBind implements AcceptInterface
{
public function __construct(private AopBind $bind)
{
}
/**
* Instantiate interceptors
*
* @return MethodInterceptorBindings
*/
public function inject(Container $container): array
{
$bindings = $this->bind->getBindings();
$instantiatedBindings = [];
foreach ($bindings as $methodName => $interceptorClassNames) {
$interceptors = [];
foreach ($interceptorClassNames as $interceptorClassName) {
/** @var class-string $interceptorClassName */
$interceptor = $container->getInstance($interceptorClassName);
assert($interceptor instanceof MethodInterceptor);
$interceptors[] = $interceptor;
}
$instantiatedBindings[$methodName] = $interceptors;
}
return $instantiatedBindings;
}
/** @inheritDoc */
public function accept(VisitorInterface $visitor): void
{
$visitor->visitAspectBind($this->bind);
}
}
================================================
FILE: src/di/AssistedInjectInterceptor.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Aop\MethodInterceptor;
use Ray\Aop\MethodInvocation;
use Ray\Di\Di\Assisted;
use Ray\Di\Di\Inject;
use Ray\Di\Di\InjectInterface;
use Ray\Di\Di\Named;
use ReflectionAttribute;
use ReflectionNamedType;
use ReflectionParameter;
use function assert;
use function call_user_func_array;
use function in_array;
use function is_callable;
/**
* @psalm-import-type NamedArguments from Types
* @psalm-import-type InjectableValue from Types
*/
/**
* Assisted injection interceptor for #[Inject] attributed parameter
*
* @psalm-import-type NamedArguments from Types
*/
final class AssistedInjectInterceptor implements MethodInterceptor
{
public function __construct(private InjectorInterface $injector, private MethodInvocationProvider $methodInvocationProvider)
{
}
/**
* @return mixed
*/
public function invoke(MethodInvocation $invocation)
{
$this->methodInvocationProvider->set($invocation);
$params = $invocation->getMethod()->getParameters();
$namedArguments = $this->getNamedArguments($invocation);
foreach ($params as $param) {
/** @var list<ReflectionAttribute> $inject */
$inject = $param->getAttributes(InjectInterface::class, ReflectionAttribute::IS_INSTANCEOF); // @phpstan-ignore-line
/** @var list<ReflectionAttribute> $assisted */
$assisted = $param->getAttributes(Assisted::class);
if (isset($assisted[0]) || isset($inject[0])) {
/** @psalm-suppress MixedAssignment */
$namedArguments[$param->getName()] = $this->getDependency($param);
}
}
$callable = [$invocation->getThis(), $invocation->getMethod()->getName()];
assert(is_callable($callable));
return call_user_func_array($callable, $namedArguments);
}
/**
* @param MethodInvocation<object> $invocation
*
* @return array<string, mixed>
*/
private function getNamedArguments(MethodInvocation $invocation): array
{
$args = $invocation->getArguments();
$params = $invocation->getMethod()->getParameters();
$namedParams = [];
foreach ($params as $param) {
$pos = $param->getPosition();
if (isset($args[$pos])) {
/** @psalm-suppress MixedAssignment */
$namedParams[$param->getName()] = $args[$pos];
}
}
return $namedParams;
}
/**
* @return mixed
*/
private function getDependency(ReflectionParameter $param)
{
$named = (string) $this->getName($param);
$type = $param->getType();
assert($type instanceof ReflectionNamedType || $type === null);
$typeName = $type instanceof ReflectionNamedType ? $type->getName() : '';
$interface = in_array($typeName, Argument::UNBOUND_TYPE) ? '' : $typeName;
/** @var class-string $interface */
return $this->injector->getInstance($interface, $named);
}
private function getName(ReflectionParameter $param): ?string
{
/** @var list<ReflectionAttribute> $nameds */
$nameds = $param->getAttributes(Named::class);
if (isset($nameds[0])) {
$named = $nameds[0]->newInstance();
assert($named instanceof Named);
return $named->value;
}
if ($param->getAttributes(Inject::class)) {
return null;
}
return $this->getCustomInject($param);
}
/**
* @return ?class-string
*/
private function getCustomInject(ReflectionParameter $param): ?string
{
/** @var list<ReflectionAttribute> $injects */
$injects = $param->getAttributes(InjectInterface::class, ReflectionAttribute::IS_INSTANCEOF);
if (! $injects) {
return null;
}
$inject = $injects[0]->newInstance();
assert($inject instanceof InjectInterface);
return $inject::class;
}
}
================================================
FILE: src/di/AssistedInjectModule.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Di\Matcher\AssistedInjectMatcher;
/**
* Assisted module for php8 attributes
*/
final class AssistedInjectModule extends AbstractModule
{
protected function configure(): void
{
$this->bindInterceptor(
$this->matcher->any(),
(new AssistedInjectMatcher()),
[AssistedInjectInterceptor::class]
);
}
}
================================================
FILE: src/di/AssistedModule.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Aop\MethodInvocation;
/**
* Module for assisted injection using PHP 8 attributes
*
* This module enables assisted injection by delegating to AssistedInjectModule
* and provides necessary bindings for method invocation context.
* Use #[Assisted] attribute on method parameters to enable automatic injection.
*/
final class AssistedModule extends AbstractModule
{
protected function configure(): void
{
$this->install(new AssistedInjectModule());
$this->bind(MethodInvocation::class)->toProvider(MethodInvocationProvider::class)->in(Scope::SINGLETON);
$this->bind(MethodInvocationProvider::class)->in(Scope::SINGLETON);
}
}
================================================
FILE: src/di/Bind.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Aop\MethodInterceptor;
use Ray\Aop\ReflectionClass;
use ReflectionException;
use ReflectionMethod;
use Stringable;
use function assert;
use function class_exists;
use function interface_exists;
/**
* @psalm-import-type BindableInterface from Types
* @psalm-import-type BindingName from Types
* @psalm-import-type ParameterNameMapping from Types
*/
final class Bind implements Stringable
{
private string $name = Name::ANY;
private DependencyInterface $bound;
private readonly BindValidator $validate;
/** @var ?Untarget */
private $untarget;
/**
* @param Container $container dependency container
* @param BindableInterface $interface interface or concrete class name
* @phpstan-param class-string<MethodInterceptor>|string $interface
*/
public function __construct(
private readonly Container $container,
private readonly string $interface
) {
$this->validate = new BindValidator();
$bindUntarget = class_exists($this->interface) && ! (new \ReflectionClass($this->interface))->isAbstract() && ! $this->isRegistered($this->interface);
$this->bound = new NullDependency();
if ($bindUntarget) {
/** @var class-string $interface */
$interface = $this->interface;
$this->untarget = new Untarget($interface);
return;
}
$this->validate->constructor($this->interface);
}
public function __destruct()
{
if ($this->untarget) {
($this->untarget)($this->container, $this);
$this->untarget = null;
}
}
/**
* @return non-empty-string
*/
public function __toString(): string
{
return $this->interface . '-' . $this->name;
}
/**
* Set dependency name
*
* @param BindingName $name
*/
public function annotatedWith(string $name): self
{
$this->name = $name;
return $this;
}
/**
* Bind to class
*
* @param class-string $class
*/
public function to(string $class): self
{
$this->untarget = null;
$refClass = $this->validate->to($this->interface, $class);
$this->bound = (new DependencyFactory())->newAnnotatedDependency($refClass);
$this->container->add($this);
return $this;
}
/**
* Bind to constructor
*
* @param class-string<T> $class class name
* @param ParameterNameMapping|string $name "varName=bindName,..." or [$varName => $bindName, $varName => $bindName...]
*
* @throws ReflectionException
*
* @template T of object
*/
public function toConstructor(string $class, string|array $name, ?InjectionPoints $injectionPoints = null, ?string $postConstruct = null): self
{
$this->untarget = null;
$postConstructRef = $postConstruct !== null ? new ReflectionMethod($class, $postConstruct) : null;
/** @var ReflectionClass<object> $reflection */
$reflection = new ReflectionClass($class);
$this->bound = (new DependencyFactory())->newToConstructor($reflection, $name, $injectionPoints, $postConstructRef);
$this->container->add($this);
return $this;
}
/**
* Bind to provider
*
* @phpstan-param class-string $provider
*/
public function toProvider(string $provider, string $context = ''): self
{
$this->untarget = null;
$refClass = $this->validate->toProvider($provider);
$this->bound = (new DependencyFactory())->newProvider($refClass, $context);
$this->container->add($this);
return $this;
}
/**
* Bind to instance
*
* @param mixed $instance
*/
public function toInstance($instance): self
{
$this->untarget = null;
$this->bound = new Instance($instance);
$this->container->add($this);
return $this;
}
/**
* Bind to NullObject
*/
public function toNull(): self
{
$this->untarget = null;
assert(interface_exists($this->interface));
$this->bound = new NullObjectDependency($this->interface);
$this->container->add($this);
return $this;
}
/**
* Set scope
*/
public function in(string $scope): self
{
if ($this->bound instanceof Dependency || $this->bound instanceof DependencyProvider || $this->bound instanceof NullDependency) {
$this->bound->setScope($scope);
}
if ($this->untarget) {
$this->untarget->setScope($scope);
}
return $this;
}
public function getBound(): DependencyInterface
{
return $this->bound;
}
public function setBound(DependencyInterface $bound): void
{
$this->bound = $bound;
}
private function isRegistered(string $interface): bool
{
return isset($this->container->getContainer()[$interface . '-' . Name::ANY]);
}
}
================================================
FILE: src/di/BindValidator.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Aop\MethodInterceptor;
use Ray\Aop\NullInterceptor;
use Ray\Aop\ReflectionClass;
use Ray\Di\Exception\InvalidProvider;
use Ray\Di\Exception\InvalidType;
use Ray\Di\Exception\NotFound;
use function class_exists;
use function interface_exists;
use function sprintf;
final class BindValidator
{
public function constructor(string $interface): void
{
if ($interface && ! interface_exists($interface) && ! class_exists($interface)) {
throw new NotFound($interface);
}
}
/**
* To validator
*
* @param class-string<T> $class
*
* @return ReflectionClass<T>
*
* @template T of object
*/
public function to(string $interface, string $class): ReflectionClass
{
if (! class_exists($class)) {
throw new NotFound($class);
}
if (! $this->isNullInterceptorBinding($class, $interface) && interface_exists($interface) && ! (new ReflectionClass($class))->implementsInterface($interface)) {
throw new InvalidType(sprintf('[%s] is no implemented [%s] interface', $class, $interface));
}
return new ReflectionClass($class);
}
/**
* toProvider validator
*
* @phpstan-param class-string $provider
*
* @psalm-return ReflectionClass
* @phpstan-return ReflectionClass<object>
*
* @throws NotFound
*/
public function toProvider(string $provider): ReflectionClass
{
if (! class_exists($provider)) {
/** @psalm-suppress MixedArgument -- should be string */
throw new NotFound($provider);
}
$reflectioClass = new ReflectionClass($provider);
if (! $reflectioClass->implementsInterface(ProviderInterface::class)) {
throw new InvalidProvider($provider);
}
return $reflectioClass;
}
private function isNullInterceptorBinding(string $class, string $interface): bool
{
return $class === NullInterceptor::class && interface_exists($interface) && (new ReflectionClass($interface))->implementsInterface(MethodInterceptor::class);
}
}
================================================
FILE: src/di/BuiltinModule.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Di\MultiBinding\MultiBindingModule;
final class BuiltinModule
{
public function __invoke(AbstractModule $module): AbstractModule
{
$module->install(new AssistedModule());
$module->install(new ProviderSetModule());
$module->install(new MultiBindingModule());
return $module;
}
}
================================================
FILE: src/di/CompileNullObject.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
/**
* Convert NullObjectDependency to Dependency
*/
final class CompileNullObject
{
public function __invoke(Container $container, string $scriptDir): void
{
$container->map(static function (DependencyInterface $dependency) use ($scriptDir): Dependency|DependencyInterface {
if ($dependency instanceof NullObjectDependency) {
return $dependency->toNull($scriptDir);
}
return $dependency;
});
}
}
================================================
FILE: src/di/Container.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use BadMethodCallException;
use Ray\Aop\Compiler;
use Ray\Aop\CompilerInterface;
use Ray\Aop\Pointcut;
use Ray\Di\Exception\NoHint;
use Ray\Di\Exception\Unbound;
use Ray\Di\Exception\Untargeted;
use Ray\Di\MultiBinding\MultiBindings;
use ReflectionClass;
use function array_merge;
use function class_exists;
use function explode;
use function ksort;
use function sprintf;
/**
* @psalm-import-type DependencyContainer from Types
* @psalm-import-type PointcutList from Types
* @psalm-import-type DependencyIndex from Types
* @psalm-import-type MethodArguments from Types
* @psalm-import-type InjectableValue from Types
*/
final class Container implements InjectorInterface
{
/** @var MultiBindings */
public $multiBindings;
/** @var DependencyContainer */
private array $container = [];
/** @var array<int, Pointcut> */
private array $pointcuts = [];
public function __construct()
{
$this->multiBindings = new MultiBindings();
}
/**
* @return list<string>
*/
public function __sleep()
{
return ['container', 'pointcuts', 'multiBindings'];
}
/**
* Add binding to a container
*/
public function add(Bind $bind): void
{
$dependency = $bind->getBound();
$dependency->register($this->container, $bind);
}
/**
* Add Pointcut to container
*/
public function addPointcut(Pointcut $pointcut): void
{
$this->pointcuts[] = $pointcut;
}
/**
* {@inheritDoc}
*
* @param ''|class-string<T> $interface
* @param string $name
*
* @return ($interface is '' ? mixed : T)
*
* @template T of object
*/
public function getInstance($interface, $name = Name::ANY)
{
/** @psalm-suppress MixedReturnStatement */
return $this->getDependency($interface . '-' . $name);
}
/**
* Return dependency injected instance
*
* @param MethodArguments $params
*
* @return mixed
*
* @throws Unbound
*/
public function getInstanceWithArgs(string $interface, array $params)
{
$index = $interface . '-';
if (! isset($this->container[$index])) {
throw $this->unbound($index);
}
$dependency = $this->container[$index];
if (! $dependency instanceof Dependency) {
throw new BadMethodCallException($interface);
}
return $dependency->injectWithArgs($this, $params);
}
/**
* Return dependency injected instance
*
* @param DependencyIndex $index
*
* @return mixed
*
* @throws Unbound
*/
public function getDependency(string $index)
{
if (! isset($this->container[$index])) {
throw $this->unbound($index);
}
return $this->container[$index]->inject($this);
}
/**
* Rename existing dependency interface + name
*/
public function move(string $sourceInterface, string $sourceName, string $targetInterface, string $targetName): void
{
$sourceIndex = $sourceInterface . '-' . $sourceName;
if (! isset($this->container[$sourceIndex])) {
throw $this->unbound($sourceIndex);
}
$targetIndex = $targetInterface . '-' . $targetName;
$this->container[$targetIndex] = $this->container[$sourceIndex];
unset($this->container[$sourceIndex]);
}
/**
* Return Unbound exception
*
* @param DependencyIndex $index {interface}-{bind name}
*/
public function unbound(string $index): Untargeted|Unbound
{
[$class, $name] = explode('-', $index);
if (class_exists($class) && ! (new ReflectionClass($class))->isAbstract()) {
return new Untargeted($class);
}
if ($class === '' && $name === '') {
return new NoHint();
}
return new Unbound(sprintf("'%s-%s'", $class, $name));
}
/**
* Return container
*
* @return array<non-empty-string, DependencyInterface>
* @psalm-return DependencyContainer
*/
public function getContainer(): array
{
return $this->container;
}
/**
* Return pointcuts
*
* @return array<int, Pointcut>
* @psalm-return PointcutList
*/
public function getPointcuts(): array
{
return $this->pointcuts;
}
/**
* Merge container
*/
public function merge(self $container): void
{
$this->multiBindings->merge($container->multiBindings);
$this->container += $container->getContainer();
$this->pointcuts = array_merge($this->pointcuts, $container->getPointcuts());
}
/**
* Weave aspects to all dependency in container
*/
public function weaveAspects(CompilerInterface $compiler): void
{
if ($this->pointcuts === []) {
return;
}
foreach ($this->container as $dependency) {
if ($dependency instanceof Dependency) {
$dependency->weaveAspects($compiler, $this->pointcuts);
}
}
}
/**
* Weave aspect to single dependency
*/
public function weaveAspect(Compiler $compiler, Dependency $dependency): self
{
$dependency->weaveAspects($compiler, $this->pointcuts);
return $this;
}
/**
* @param callable(DependencyInterface, string): DependencyInterface $f
*/
public function map(callable $f): void
{
foreach ($this->container as $key => &$index) {
$index = $f($index, $key);
}
}
public function sort(): void
{
ksort($this->container);
}
}
================================================
FILE: src/di/ContainerFactory.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Aop\Compiler;
use function array_shift;
/**
* @psalm-import-type ModuleList from Types
* @psalm-import-type ScriptDir from Types
*/
final class ContainerFactory
{
/**
* @param AbstractModule|ModuleList|null $module Module(s)
* @param ScriptDir $classDir
*/
public function __invoke($module, string $classDir): Container
{
$oneModule = $this->getModule($module);
// install built-in module
$appModule = (new BuiltinModule())($oneModule);
$container = $appModule->getContainer();
// Compile null objects
(new CompileNullObject())($container, $classDir);
// Compile aspects
/** @psalm-suppress InvalidArgument */
$container->weaveAspects(new Compiler($classDir));
return $container;
}
/**
* @param AbstractModule|ModuleList|null $module Module(s)
*/
private function getModule($module): AbstractModule
{
if ($module instanceof AbstractModule) {
return $module;
}
if ($module === null) {
return new NullModule();
}
$modules = $module;
$oneModule = array_shift($modules);
foreach ($modules as $module) {
$oneModule->install($module);
}
return $oneModule;
}
}
================================================
FILE: src/di/Dependency.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Aop\Bind as AopBind;
use Ray\Aop\CompilerInterface;
use Ray\Aop\MethodInterceptor;
use Ray\Aop\WeavedInterface;
use ReflectionClass;
use ReflectionMethod;
use function assert;
use function method_exists;
use function sprintf;
/**
* @psalm-import-type MethodArguments from Types
* @psalm-import-type PointcutList from Types
*/
final class Dependency implements DependencyInterface, AcceptInterface
{
/** @var NewInstance */
private $newInstance;
/** @var ?string */
private $postConstruct;
private bool $isSingleton = false;
/** @var ?mixed */
private $instance;
public function __construct(NewInstance $newInstance, ?ReflectionMethod $postConstruct = null)
{
$this->newInstance = $newInstance;
$this->postConstruct = $postConstruct->name ?? null;
}
/**
* @return array<string>
*/
public function __sleep()
{
return ['newInstance', 'postConstruct', 'isSingleton'];
}
public function __toString(): string
{
return sprintf(
'(dependency) %s',
(string) $this->newInstance
);
}
/**
* {@inheritdoc}
*/
public function register(array &$container, Bind $bind): void
{
$container[(string) $bind] = $bind->getBound();
}
/**
* {@inheritdoc}
*/
public function inject(Container $container)
{
// singleton ?
if ($this->isSingleton === true && $this->instance !== null) {
return $this->instance;
}
// create dependency injected instance
$this->instance = ($this->newInstance)($container);
// @PostConstruct
if ($this->postConstruct !== null) {
assert(method_exists($this->instance, $this->postConstruct));
$this->instance->{$this->postConstruct}();
}
return $this->instance;
}
/**
* @param MethodArguments $params
*
* @return mixed
*/
public function injectWithArgs(Container $container, array $params)
{
// singleton ?
if ($this->isSingleton === true && $this->instance !== null) {
return $this->instance;
}
// create dependency injected instance
$this->instance = $this->newInstance->newInstanceArgs($container, $params);
// @PostConstruct
if ($this->postConstruct !== null) {
assert(method_exists($this->instance, $this->postConstruct));
$this->instance->{$this->postConstruct}();
}
return $this->instance;
}
/**
* {@inheritdoc}
*/
public function setScope($scope): void
{
if ($scope === Scope::SINGLETON) {
$this->isSingleton = true;
}
}
/**
* @param PointcutList $pointcuts
*/
public function weaveAspects(CompilerInterface $compiler, array $pointcuts): void
{
$class = (string) $this->newInstance;
if ((new ReflectionClass($class))->isFinal()) {
return;
}
$isInterceptor = (new ReflectionClass($class))->implementsInterface(MethodInterceptor::class);
$isWeaved = (new ReflectionClass($class))->implementsInterface(WeavedInterface::class);
if ($isInterceptor || $isWeaved) {
return;
}
$bind = new AopBind();
$className = (string) $this->newInstance;
$bind->bind($className, $pointcuts);
if (! $bind->getBindings()) {
return;
}
$class = $compiler->compile($className, $bind);
$this->newInstance->weaveAspects($class, $bind);
}
/** @inheritDoc */
public function accept(VisitorInterface $visitor)
{
return $visitor->visitDependency(
$this->newInstance,
$this->postConstruct,
$this->isSingleton
);
}
public function isSingleton(): bool
{
return $this->isSingleton;
}
}
================================================
FILE: src/di/DependencyFactory.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Aop\ReflectionClass;
use ReflectionMethod;
use function assert;
use function class_exists;
final class DependencyFactory
{
/**
* Create dependency object
*
* @param ReflectionClass<object> $class
*/
public function newAnnotatedDependency(ReflectionClass $class): Dependency
{
$annotateClass = new AnnotatedClass();
$newInstance = $annotateClass->getNewInstance($class);
$postConstruct = $annotateClass->getPostConstruct($class);
return new Dependency($newInstance, $postConstruct);
}
/**
* Create Provider binding
*
* @param ReflectionClass<object> $provider
*/
public function newProvider(ReflectionClass $provider, string $context): DependencyProvider
{
$dependency = $this->newAnnotatedDependency($provider);
return new DependencyProvider($dependency, $context);
}
/**
* Create ToConstructor binding
*
* @param ReflectionClass<object> $class
* @param string|array<string, string> $name
*/
public function newToConstructor(
ReflectionClass $class,
string|array $name,
?InjectionPoints $injectionPoints = null,
?ReflectionMethod $postConstruct = null
): Dependency {
assert(class_exists($class->name));
$setterMethods = $injectionPoints instanceof InjectionPoints ? $injectionPoints($class->name) : new SetterMethods([]);
$newInstance = new NewInstance($class, $setterMethods, new Name($name));
return new Dependency($newInstance, $postConstruct);
}
}
================================================
FILE: src/di/DependencyInterface.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
/**
* @psalm-import-type DependencyContainer from Types
* @psalm-import-type ScopeType from Types
* @psalm-import-type InjectableValue from Types
*/
interface DependencyInterface
{
/**
* @return string
*/
public function __toString();
/**
* Inject dependencies into dependent objects
*
* @return mixed
*/
public function inject(Container $container);
/**
* Register dependency to container
*
* @param DependencyContainer $container
*
* @return void
*
* @param-out DependencyContainer $container
*/
public function register(array &$container, Bind $bind);
/**
* Set scope
*
* @param string $scope
*
* @return void
*/
public function setScope($scope);
}
================================================
FILE: src/di/DependencyProvider.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use function assert;
use function sprintf;
final class DependencyProvider implements DependencyInterface, AcceptInterface
{
private bool $isSingleton = false;
/** @var ?mixed */
private $instance;
public function __construct(
/**
* Provider dependency
*/
private readonly Dependency $dependency,
public string $context
) {
}
/**
* @return list<string>
*/
public function __sleep()
{
return ['context', 'dependency', 'isSingleton'];
}
public function __toString(): string
{
return sprintf(
'(provider) %s',
(string) $this->dependency
);
}
/**
* {@inheritdoc}
*/
public function register(array &$container, Bind $bind): void
{
$container[(string) $bind] = $bind->getBound();
}
/**
* {@inheritdoc}
*/
public function inject(Container $container)
{
if ($this->isSingleton && $this->instance !== null) {
return $this->instance;
}
$provider = $this->dependency->inject($container);
assert($provider instanceof ProviderInterface);
if ($provider instanceof SetContextInterface) {
$this->setContext($provider);
}
$this->instance = $provider->get();
return $this->instance;
}
/**
* {@inheritdoc}
*/
public function setScope($scope): void
{
if ($scope === Scope::SINGLETON) {
$this->isSingleton = true;
}
}
public function setContext(SetContextInterface $provider): void
{
$provider->setContext($this->context);
}
public function isSingleton(): bool
{
return $this->isSingleton;
}
/** @inheritDoc */
public function accept(VisitorInterface $visitor)
{
return $visitor->visitProvider(
$this->dependency,
$this->context,
$this->isSingleton
);
}
}
================================================
FILE: src/di/Di/Assisted.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Di;
use Attribute;
/**
* Marks a parameter for assisted injection
*
* When applied to a method parameter, this indicates that the parameter
* should be automatically injected by the DI container during method invocation.
*/
#[Attribute(Attribute::TARGET_PARAMETER)]
final class Assisted
{
}
================================================
FILE: src/di/Di/Inject.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Di;
use Attribute;
/**
* Annotates your class methods into which the Injector should inject values
*
* @psalm-immutable
*/
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_PARAMETER)]
final class Inject implements InjectInterface
{
/**
* @SuppressWarnings("PHPMD.BooleanArgumentFlag")
*/
public function __construct(
/**
* If true, and the appropriate binding is not found, the Injector will skip injection of this method or field rather than produce an error.
*/
public bool $optional = false
) {
}
/**
* {@inheritdoc}
*/
public function isOptional(): bool
{
return $this->optional;
}
}
================================================
FILE: src/di/Di/InjectInterface.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Di;
interface InjectInterface
{
/**
* Whether or not to use optional injection
*
* @return bool
*/
public function isOptional();
}
================================================
FILE: src/di/Di/Named.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Di;
use Attribute;
/**
* Annotates named things
*
* @psalm-immutable
*/
#[Attribute(Attribute::TARGET_PARAMETER | Attribute::TARGET_METHOD | Attribute::TARGET_PROPERTY)]
final class Named
{
public function __construct(public string $value)
{
}
}
================================================
FILE: src/di/Di/PostConstruct.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Di;
use Attribute;
/**
* PostConstruct
*
* The PostConstruct annotation is used on a method that needs to be executed after dependency injection is done to
* perform any initialization. This method MUST be invoked before the class is put into service. The method annotated
* with PostConstruct MUST be invoked even if the class does not request any resources to be injected. Only one method
* can be annotated with this annotation. The method on which the PostConstruct annotation is applied MUST fulfill
* all of the following criteria
*
* - The method MUST NOT have any parameters.
* - The return type of the method MUST be void.
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class PostConstruct
{
}
================================================
FILE: src/di/Di/Qualifier.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Di;
use Attribute;
/**
* Identifies qualifier annotations
*/
#[Attribute(Attribute::TARGET_CLASS)]
final class Qualifier
{
}
================================================
FILE: src/di/Di/Set.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Di;
use Attribute;
/**
* @template T of object
* @psalm-immutable
*/
#[Attribute(Attribute::TARGET_PARAMETER | Attribute::TARGET_PROPERTY)]
final class Set
{
/**
* @param ''|class-string<T> $interface
*/
public function __construct(public string $interface, public string $name = '')
{
}
}
================================================
FILE: src/di/Exception/DirectoryNotWritable.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Exception;
use RuntimeException;
final class DirectoryNotWritable extends RuntimeException implements ExceptionInterface
{
}
================================================
FILE: src/di/Exception/ExceptionInterface.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Exception;
interface ExceptionInterface
{
}
================================================
FILE: src/di/Exception/InvalidContext.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Exception;
use InvalidArgumentException;
final class InvalidContext extends InvalidArgumentException implements ExceptionInterface
{
}
================================================
FILE: src/di/Exception/InvalidProvider.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Exception;
use InvalidArgumentException;
final class InvalidProvider extends InvalidArgumentException implements ExceptionInterface
{
}
================================================
FILE: src/di/Exception/InvalidToConstructorNameParameter.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Exception;
use InvalidArgumentException;
/**
* @see https://github.com/ray-di/Ray.Di#constructor-bindings
*/
final class InvalidToConstructorNameParameter extends InvalidArgumentException implements ExceptionInterface
{
}
================================================
FILE: src/di/Exception/InvalidType.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Exception;
use InvalidArgumentException;
final class InvalidType extends InvalidArgumentException implements ExceptionInterface
{
}
================================================
FILE: src/di/Exception/MethodInvocationNotAvailable.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Exception;
final class MethodInvocationNotAvailable extends Unbound
{
}
================================================
FILE: src/di/Exception/NoHint.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Exception;
/**
* Exception thrown when a parameter has no type hint and no binding name
*
* Message format: ${var} (file:line)
*
* This occurs when Ray.Di cannot identify what to inject because
* the parameter has neither a class/interface type hint nor a #[Named] or #[Qualifier] attribute.
*/
final class NoHint extends Unbound
{
}
================================================
FILE: src/di/Exception/NotFound.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Exception;
use LogicException;
final class NotFound extends LogicException implements ExceptionInterface
{
}
================================================
FILE: src/di/Exception/SetNotFound.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Exception;
use LogicException;
final class SetNotFound extends LogicException implements ExceptionInterface
{
}
================================================
FILE: src/di/Exception/Unbound.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Exception;
use Exception;
use LogicException;
use function array_pop;
use function array_reverse;
use function implode;
use function sprintf;
/**
* Exception thrown when a binding is not found
*
* Message format: '{type}-{name}' in file:line ($var)
*
* Examples:
* - "'FooInterface-' in file.php:10 ($foo)" - FooInterface with no name
* - "'FooInterface-db' in file.php:10 ($foo)" - FooInterface with name 'db'
* - "'-db' in file.php:10 ($foo)" - no type with name 'db'
*/
class Unbound extends LogicException implements ExceptionInterface
{
public function __toString(): string
{
$messages = [sprintf("- %s\n", $this->getMessage())];
$e = $this->getPrevious();
if (! $e instanceof Exception) {
return $this->getMainMessage($this);
}
if ($e instanceof self) {
return $this->buildMessage($e, $messages) . "\n" . $e->getTraceAsString();
}
return parent::__toString();
}
/**
* @param array<int, string> $msg
*/
private function buildMessage(self $e, array $msg): string
{
$lastE = $e;
while ($e instanceof self) {
$msg[] = sprintf("- %s\n", $e->getMessage());
$lastE = $e;
$e = $e->getPrevious();
}
array_pop($msg);
$msg = array_reverse($msg);
return $this->getMainMessage($lastE) . implode('', $msg);
}
/**
* @psalm-pure
*/
private function getMainMessage(self $e): string
{
return sprintf(
"exception '%s' with message '%s'\n",
$e::class,
$e->getMessage()
);
}
}
================================================
FILE: src/di/Exception/Untargeted.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Exception;
final class Untargeted extends Unbound
{
}
================================================
FILE: src/di/Exception.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
final class Exception extends \Exception
{
}
================================================
FILE: src/di/Grapher.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Aop\Compiler;
use function file_exists;
use function spl_autoload_register;
use function sprintf;
use function str_replace;
/**
* @psalm-import-type MethodArguments from Types
* @psalm-import-type ScriptDir from Types
*/
final class Grapher
{
private Container $container;
/**
* @param AbstractModule $module Binding module
* @param ScriptDir $classDir Class directory
*/
public function __construct(AbstractModule $module, private string $classDir)
{
$module->install(new AssistedModule());
$this->container = $module->getContainer();
/** @psalm-suppress InvalidArgument */
$this->container->weaveAspects(new Compiler($this->classDir));
// builtin injection
(new Bind($this->container, InjectorInterface::class))->toInstance(new Injector($module));
}
/**
* Wakeup
*/
public function __wakeup()
{
spl_autoload_register(
function (string $class): void {
$file = sprintf('%s/%s.php', $this->classDir, str_replace('\\', '_', $class));
if (file_exists($file)) {
include $file; //@codeCoverageIgnore
}
}
);
}
/**
* Build an object graph with give constructor parameters
*
* @param string $class class name
* @param list<mixed> $params construct parameters (MethodArguments)
*
* @return mixed
*/
public function newInstanceArgs(string $class, array $params)
{
return $this->container->getInstanceWithArgs($class, $params);
}
}
================================================
FILE: src/di/InjectableInterface.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
interface InjectableInterface
{
}
================================================
FILE: src/di/InjectionPoint.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Aop\ReflectionClass;
use Ray\Aop\ReflectionMethod;
use Ray\Di\Di\Qualifier;
use ReflectionParameter;
use function assert;
use function class_exists;
final class InjectionPoint implements InjectionPointInterface
{
private string $pClass;
/** @var string */
private $pFunction;
/** @var string */
private $pName;
public function __construct(private ReflectionParameter $parameter)
{
$this->pFunction = $this->parameter->getDeclaringFunction()->name;
$class = $this->parameter->getDeclaringClass();
$this->pClass = $class instanceof ReflectionClass ? $class->name : '';
$this->pName = $this->parameter->name;
}
/**
* {@inheritdoc}
*/
public function getParameter(): ReflectionParameter
{
return $this->parameter;
}
/**
* {@inheritdoc}
*/
public function getMethod(): ReflectionMethod
{
$this->parameter = $this->getParameter();
$class = $this->parameter->getDeclaringClass();
$method = $this->parameter->getDeclaringFunction()->getShortName();
assert($class instanceof \ReflectionClass);
assert(class_exists($class->getName()));
return new ReflectionMethod($class->getName(), $method);
}
/**
* {@inheritdoc}
*/
public function getClass(): ReflectionClass
{
$this->parameter = $this->getParameter();
$class = $this->parameter->getDeclaringClass();
assert($class instanceof \ReflectionClass);
return new ReflectionClass($class->getName());
}
/**
* {@inheritdoc}
*/
public function getQualifiers(): array
{
$qualifiers = [];
$annotations = $this->getMethod()->getAnnotations();
foreach ($annotations as $annotation) {
$maybeQualifier = (new ReflectionClass($annotation))->getAnnotation(Qualifier::class);
if ($maybeQualifier instanceof Qualifier) {
$qualifiers[] = $annotation;
}
}
return $qualifiers;
}
/**
* @return array<string>
*/
public function __serialize(): array
{
return [$this->pClass, $this->pFunction, $this->pName];
}
/**
* @param array<string> $array
*/
public function __unserialize(array $array): void
{
[$this->pClass, $this->pFunction, $this->pName] = $array;
}
}
================================================
FILE: src/di/InjectionPointInterface.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Aop\ReflectionClass;
use Ray\Aop\ReflectionMethod;
use ReflectionParameter;
/**
* @psalm-import-type QualifierList from Types
*/
interface InjectionPointInterface
{
/**
* Return parameter reflection
*/
public function getParameter(): ReflectionParameter;
/**
* Return method reflection
*/
public function getMethod(): ReflectionMethod;
/**
* Return class reflection
*
* @psalm-return ReflectionClass
* @phpstan-return ReflectionClass<object>
*/
public function getClass(): ReflectionClass;
/**
* Return Qualifier annotations
*
* @return QualifierList
*/
public function getQualifiers(): array;
}
================================================
FILE: src/di/InjectionPoints.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use ReflectionException;
use ReflectionMethod;
/**
* @psalm-import-type InjectionPointDefinition from Types
* @psalm-import-type InjectionPointsList from Types
*/
final class InjectionPoints
{
/**
* Injection points
*
* @var InjectionPointsList
*/
private array $points = [];
/**
* @param class-string $class
*
* @throws ReflectionException
*/
public function __invoke(string $class): SetterMethods
{
$points = [];
foreach ($this->points as $point) {
$points[] = $this->getSetterMethod($class, $point);
}
return new SetterMethods($points);
}
public function addMethod(string $method, string $name = Name::ANY): self
{
$this->points[] = [$method, $name, false];
return $this;
}
public function addOptionalMethod(string $method, string $name = Name::ANY): self
{
$this->points[] = [$method, $name, true];
return $this;
}
/**
* @param class-string $class
* @param InjectionPointDefinition $point
*
* @throws ReflectionException
*/
private function getSetterMethod(string $class, array $point): SetterMethod
{
$setterMethod = new SetterMethod(new ReflectionMethod($class, $point[0]), new Name($point[1]));
if ($point[2]) {
$setterMethod->setOptional();
}
return $setterMethod;
}
}
================================================
FILE: src/di/Injector.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Aop\Compiler;
use Ray\Di\Exception\DirectoryNotWritable;
use Ray\Di\Exception\Untargeted;
use function assert;
use function file_exists;
use function is_dir;
use function is_writable;
use function spl_autoload_register;
use function sprintf;
use function str_replace;
use function sys_get_temp_dir;
/**
* @psalm-import-type BindableInterface from Types
* @psalm-import-type ModuleList from Types
* @psalm-import-type ScriptDir from Types
*/
final class Injector implements InjectorInterface
{
/** @var ScriptDir */
private readonly string $classDir;
private readonly Container $container;
/**
* @param AbstractModule|ModuleList|null $module Module(s)
* @param string $tmpDir Temp directory for generated class
*/
public function __construct($module = null, string $tmpDir = '')
{
/** @var ScriptDir $classDir */
$classDir = is_dir($tmpDir) ? $tmpDir : sys_get_temp_dir();
if (! is_writable($classDir)) {
throw new DirectoryNotWritable($classDir); // @codeCoverageIgnore
}
$this->classDir = $classDir;
$this->container = (new ContainerFactory())($module, $this->classDir);
// Bind injector (built-in bindings)
(new Bind($this->container, InjectorInterface::class))->toInstance($this);
$this->container->sort();
}
/**
* Wakeup
*/
public function __wakeup()
{
spl_autoload_register(
function (string $class): void {
$file = sprintf('%s/%s.php', $this->classDir, str_replace('\\', '_', $class));
if (file_exists($file)) {
include $file; //@codeCoverageIgnore
}
}
);
}
/**
* {@inheritDoc}
*/
public function getInstance($interface, $name = Name::ANY)
{
try {
/** @psalm-suppress MixedAssignment */
$instance = $this->container->getInstance($interface, $name);
} catch (Untargeted) {
/** @psalm-var class-string $interface */
$this->bind($interface);
/** @psalm-suppress MixedAssignment */
$instance = $this->getInstance($interface, $name);
}
/** @psalm-suppress MixedReturnStatement */
return $instance;
}
/**
* @param BindableInterface $class
*/
private function bind(string $class): void
{
new Bind($this->container, $class);
$bound = $this->container->getContainer()[$class . '-' . Name::ANY];
assert($bound instanceof Dependency);
/** @psalm-suppress InvalidArgument */
$this->container->weaveAspect(new Compiler($this->classDir), $bound)->getInstance($class);
}
}
================================================
FILE: src/di/InjectorInterface.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
/**
* Builds the graphs of objects that make up your application
*
* The injector tracks the dependencies for each type and uses bindings to inject them.
* This is the core of Ray.Di, although you rarely interact with it directly.
* This "behind-the-scenes" operation is what distinguishes dependency injection from its cousin, the service locator pattern.
*/
interface InjectorInterface
{
/**
* Return object graph
*
* @param ''|class-string<T> $interface
* @param string $name
*
* @return ($interface is '' ? mixed : T)
*
* @template T of object
*/
public function getInstance($interface, $name = Name::ANY);
}
================================================
FILE: src/di/Instance.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use function gettype;
use function is_object;
use function is_scalar;
use function sprintf;
final class Instance implements DependencyInterface, AcceptInterface
{
/**
* @param mixed $value
*/
public function __construct(public $value)
{
}
public function __toString(): string
{
if (is_scalar($this->value)) {
return sprintf(
'(%s) %s',
gettype($this->value),
(string) $this->value
);
}
if (is_object($this->value)) {
return '(object) ' . $this->value::class;
}
return '(' . gettype($this->value) . ')';
}
/**
* {@inheritdoc}
*/
public function register(array &$container, Bind $bind): void
{
$index = (string) $bind;
$container[$index] = $bind->getBound();
}
/**
* {@inheritdoc}
*/
public function inject(Container $container)
{
return $this->value;
}
/**
* {@inheritdoc}
*
* @codeCoverageIgnore
*/
public function setScope($scope): void
{
}
/** @inheritDoc */
public function accept(VisitorInterface $visitor)
{
return $visitor->visitInstance($this->value);
}
}
================================================
FILE: src/di/Matcher/AssistedInjectMatcher.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Matcher;
use LogicException;
use Ray\Aop\AbstractMatcher;
use Ray\Di\Di\Assisted;
use Ray\Di\Di\InjectInterface;
use ReflectionAttribute;
use ReflectionClass;
use ReflectionMethod;
final class AssistedInjectMatcher extends AbstractMatcher
{
/**
* {@inheritdoc}
*
* @codeCoverageIgnore
*/
public function matchesClass(ReflectionClass $class, array $arguments): bool
{
throw new LogicException('Should not used in class matcher');
}
/**
* {@inheritdoc}
*/
public function matchesMethod(ReflectionMethod $method, array $arguments): bool
{
$params = $method->getParameters();
foreach ($params as $param) {
/** @var list<ReflectionAttribute> $attributes */
$attributes = $param->getAttributes(InjectInterface::class, ReflectionAttribute::IS_INSTANCEOF);
if (isset($attributes[0])) {
return true;
}
/** @var list<ReflectionAttribute> $assisted */
$assisted = $param->getAttributes(Assisted::class);
if (isset($assisted[0])) {
return true;
}
}
return false;
}
}
================================================
FILE: src/di/MethodInvocationProvider.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Aop\MethodInvocation;
use Ray\Di\Exception\MethodInvocationNotAvailable;
/**
* @implements ProviderInterface<MethodInvocation>
*/
final class MethodInvocationProvider implements ProviderInterface
{
/** @var ?MethodInvocation<object> */
private ?MethodInvocation $invocation = null;
/**
* @param MethodInvocation<object> $invocation
*/
public function set(MethodInvocation $invocation): void
{
$this->invocation = $invocation;
}
/**
* @return MethodInvocation<object>
*/
public function get(): MethodInvocation
{
if ($this->invocation === null) {
throw new MethodInvocationNotAvailable();
}
return $this->invocation;
}
}
================================================
FILE: src/di/ModuleString.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use function assert;
use function implode;
use function serialize;
use function sort;
use function sprintf;
use function unserialize;
use const PHP_EOL;
/**
* @psalm-import-type PointcutList from Types
*/
final class ModuleString
{
/**
* @param PointcutList $pointcuts
*/
public function __invoke(Container $container, array $pointcuts): string
{
$log = [];
/** @psalm-suppress MixedAssignment */
$container = unserialize(serialize($container), ['allowed_classes' => true]);
assert($container instanceof Container);
$spy = new SpyCompiler();
foreach ($container->getContainer() as $dependencyIndex => $dependency) {
if ($dependency instanceof Dependency) {
$dependency->weaveAspects($spy, $pointcuts);
}
$log[] = sprintf(
'%s => %s',
$dependencyIndex,
(string) $dependency
);
}
sort($log);
return implode(PHP_EOL, $log);
}
}
================================================
FILE: src/di/MultiBinder.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Di\MultiBinding\LazyInstance;
use Ray\Di\MultiBinding\LazyInterface;
use Ray\Di\MultiBinding\LazyProvider;
use Ray\Di\MultiBinding\LazyTo;
use Ray\Di\MultiBinding\MultiBindings;
/**
* @psalm-import-type BindableInterface from Types
* @psalm-import-type LazyBindingList from Types
*/
final class MultiBinder
{
private readonly Container $container;
/** @var MultiBindings */
private $multiBindings;
private ?string $key = null;
private function __construct(AbstractModule $module, private readonly string $interface)
{
$this->container = $module->getContainer();
$this->multiBindings = $this->container->multiBindings;
$this->container->add(
(new Bind($this->container, MultiBindings::class))->toInstance($this->multiBindings)
);
}
public static function newInstance(AbstractModule $module, string $interface): self
{
return new self($module, $interface);
}
public function addBinding(?string $key = null): self
{
$this->key = $key;
return $this;
}
public function setBinding(?string $key = null): self
{
$this->container->multiBindings->exchangeArray([]);
$this->key = $key;
return $this;
}
/**
* @param class-string $class
*/
public function to(string $class): void
{
$this->bind(new LazyTo($class), $this->key);
}
/**
* @param class-string<ProviderInterface<T>> $provider
*
* @template T of mixed
*/
public function toProvider(string $provider): void
{
$this->bind(new LazyProvider($provider), $this->key);
}
/**
* @param mixed $instance
*/
public function toInstance($instance): void
{
$this->bind(new LazyInstance($instance), $this->key);
}
private function bind(LazyInterface $lazy, ?string $key): void
{
$bindings = [];
if ($this->multiBindings->offsetExists($this->interface)) {
$bindings = $this->multiBindings->offsetGet($this->interface);
}
if ($key === null) {
$bindings[] = $lazy;
$this->multiBindings->offsetSet($this->interface, $bindings);
return;
}
$bindings[$key] = $lazy;
$this->multiBindings->offsetSet($this->interface, $bindings);
}
}
================================================
FILE: src/di/MultiBinding/LazyInstance.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\MultiBinding;
use Ray\Di\InjectorInterface;
/**
* @template T of mixed
* @psalm-immutable
*/
final class LazyInstance implements LazyInterface
{
/**
* @param T $instance
*/
public function __construct(private $instance)
{
}
/**
* @return T
*/
public function __invoke(InjectorInterface $injector)
{
unset($injector);
return $this->instance;
}
}
================================================
FILE: src/di/MultiBinding/LazyInterface.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\MultiBinding;
use Ray\Di\InjectorInterface;
interface LazyInterface
{
/**
* @return mixed
*/
public function __invoke(InjectorInterface $injector);
}
================================================
FILE: src/di/MultiBinding/LazyProvider.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\MultiBinding;
use Ray\Di\InjectorInterface;
use Ray\Di\ProviderInterface;
/**
* @template T of ProviderInterface
*/
final class LazyProvider implements LazyInterface
{
/**
* @param class-string<T> $class
*/
public function __construct(private string $class)
{
}
/**
* @return mixed
*/
public function __invoke(InjectorInterface $injector)
{
$provider = $injector->getInstance($this->class);
return $provider->get();
}
}
================================================
FILE: src/di/MultiBinding/LazyTo.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\MultiBinding;
use Ray\Di\InjectorInterface;
/**
* @template T of object
*/
final class LazyTo implements LazyInterface
{
/**
* @param class-string<T> $class
*/
public function __construct(private string $class)
{
}
/**
* @return T
*/
public function __invoke(InjectorInterface $injector)
{
return $injector->getInstance($this->class);
}
}
================================================
FILE: src/di/MultiBinding/Map.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\MultiBinding;
use ArrayAccess;
use Countable;
use Generator;
use Iterator;
use IteratorAggregate;
use LogicException;
use Ray\Di\InjectorInterface;
use ReturnTypeWillChange;
use function array_key_exists;
use function count;
/**
* @template T
* @implements ArrayAccess<array-key, T>
* @implements IteratorAggregate<string, mixed>
*/
final class Map implements IteratorAggregate, ArrayAccess, Countable
{
/**
* @param array<array-key, LazyInterface> $lazies
*/
public function __construct(private array $lazies, private readonly InjectorInterface $injector)
{
}
/**
* @param array-key $offset
*
* @codeCoverageIgnore
*/
#[ReturnTypeWillChange]
public function offsetExists($offset): bool
{
return array_key_exists($offset, $this->lazies);
}
/**
* @param array-key $offset
*
* @return T
*
* @codeCoverageIgnore
*/
#[ReturnTypeWillChange]
public function offsetGet($offset)
{
/** @var T $instance */
$instance = ($this->lazies[$offset])($this->injector);
return $instance;
}
/**
* @param array-key $offset
* @param mixed $value
*
* @return never
*
* @codeCoverageIgnore
*/
#[ReturnTypeWillChange]
public function offsetSet($offset, $value): void
{
unset($offset, $value);
throw new LogicException();
}
/**
* @param array-key $offset
*
* @return never
*
* @codeCoverageIgnore
*/
#[ReturnTypeWillChange]
public function offsetUnset($offset): void
{
unset($offset);
throw new LogicException();
}
/** @return Generator<array-key, T, void, void> */
public function getIterator(): Iterator
{
foreach ($this->lazies as $key => $lazy) {
/** @var T $object */
$object = ($lazy)($this->injector);
yield $key => $object;
}
}
public function count(): int
{
return count($this->lazies);
}
}
================================================
FILE: src/di/MultiBinding/MapProvider.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\MultiBinding;
use Ray\Di\Di\Set;
use Ray\Di\Exception\SetNotFound;
use Ray\Di\InjectionPointInterface;
use Ray\Di\InjectorInterface;
use Ray\Di\ProviderInterface;
/**
* @implements ProviderInterface<Map>
*/
final class MapProvider implements ProviderInterface
{
public function __construct(private readonly InjectionPointInterface $ip, private MultiBindings $multiBindings, private readonly InjectorInterface $injector)
{
}
/**
* @return Map<mixed>
*/
public function get(): Map
{
$param = $this->ip->getParameter();
$setAttribute = $param->getAttributes(Set::class);
if (! isset($setAttribute[0])) {
throw new SetNotFound((string) $param);
}
/** @var Set<object> $set */
$set = $setAttribute[0]->newInstance();
/** @var array<string, LazyTo<object>> $lazies */
$lazies = $this->multiBindings[$set->interface];
return new Map($lazies, $this->injector);
}
}
================================================
FILE: src/di/MultiBinding/MultiBindingModule.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\MultiBinding;
use Ray\Di\AbstractModule;
use Ray\Di\Types;
/**
* @psalm-import-type BindableInterface from Types
*/
final class MultiBindingModule extends AbstractModule
{
protected function configure(): void
{
$this->bind(MultiBindings::class);
$this->bind(Map::class)->toProvider(MapProvider::class);
}
}
================================================
FILE: src/di/MultiBinding/MultiBindings.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\MultiBinding;
use ArrayObject;
use Ray\Di\Types;
use function array_merge_recursive;
/**
* @psalm-import-type LazyBindingList from Types
* @extends ArrayObject<string, LazyBindingList>
*/
final class MultiBindings extends ArrayObject
{
public function merge(self $multiBindings): void
{
$this->exchangeArray(
array_merge_recursive($this->getArrayCopy(), $multiBindings->getArrayCopy())
);
}
}
================================================
FILE: src/di/Name.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Di\Di\Named;
use Ray\Di\Di\Qualifier;
use ReflectionAttribute;
use ReflectionClass;
use ReflectionException;
use ReflectionMethod;
use ReflectionParameter;
use function class_exists;
use function is_string;
use function preg_match;
/**
* @psalm-import-type ParameterNameMapping from Types
*/
final class Name
{
/**
* 'Unnamed' name
*/
public const ANY = '';
private string $name = '';
/**
* Named database
*
* format: array<varName, NamedName>
*
* @var ParameterNameMapping
*/
private array $names = [];
/**
* @param string|ParameterNameMapping $name
*/
public function __construct(string|array $name)
{
if (is_string($name)) {
$this->setName($name);
return;
}
$this->names = $name;
}
/**
* Create instance from PHP8 attributes
*
* psalm does not know ReflectionAttribute?? PHPStan produces no type error here.
*/
public static function withAttributes(ReflectionMethod $method): ?self
{
$params = $method->getParameters();
$names = [];
foreach ($params as $param) {
/** @var array<ReflectionAttribute> $attributes */
$attributes = $param->getAttributes();
if ($attributes) {
$name = self::getName($attributes);
$names[$param->name] = $name;
}
}
// Backward compatibility: Get parameter qualifiers from method-level attribute
if ($names === []) {
/** @psalm-suppress DeprecatedClass */
$names = BcParameterQualifier::getNames($method);
}
if ($names !== []) {
return new self($names);
}
return null;
}
/**
* @param non-empty-array<ReflectionAttribute> $attributes
*
* @throws ReflectionException
*
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArgument
*/
private static function getName(array $attributes): string
{
$refAttribute = $attributes[0];
$attribute = $refAttribute->newInstance();
if ($attribute instanceof Named) {
return $attribute->value;
}
$isQualifier = (bool) (new ReflectionClass($attribute))->getAttributes(Qualifier::class);
if ($isQualifier) {
return $attribute::class;
}
return '';
}
public function __invoke(ReflectionParameter $parameter): string
{
// single variable named binding
if ($this->name) {
return $this->name;
}
$parameterName = $parameter->name;
// multiple variable named binding
return $this->names[$parameterName] ?? $this->names[self::ANY] ?? self::ANY;
}
private function setName(string $name): void
{
// annotation
if (class_exists($name, false)) {
$this->name = $name;
return;
}
// single name
// @Named(name)
if ($name === self::ANY || preg_match('/^\w+$/', $name)) {
$this->name = $name;
return;
}
// name list (backward compatibility)
// @Named(varName1=name1, varName2=name2) or toConstructor string format
/** @psalm-suppress DeprecatedClass */
$this->names = BcStringParser::parse($name);
}
}
================================================
FILE: src/di/NewInstance.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Aop\Bind as AopBind;
use Ray\Aop\WeavedInterface;
use ReflectionClass;
use ReflectionException;
use Stringable;
use function assert;
/**
* @psalm-import-type MethodArguments from Types
*/
final class NewInstance implements Stringable
{
/** @var class-string */
private string $class;
/** @var SetterMethods */
private $setterMethods;
private ?Arguments $arguments = null;
private ?AspectBind $bind = null;
/**
* @phpstan-param ReflectionClass<object> $class
*/
public function __construct(
ReflectionClass $class,
SetterMethods $setterMethods,
?Name $constructorName = null
) {
$constructorName = $constructorName ?: new Name(Name::ANY);
$this->class = $class->getName();
$constructor = $class->getConstructor();
if ($constructor) {
$this->arguments = new Arguments($constructor, $constructorName);
}
$this->setterMethods = $setterMethods;
}
/**
* @throws ReflectionException
*/
public function __invoke(Container $container): object
{
$reflection = new ReflectionClass($this->class);
/** @psalm-suppress MixedMethodCall */
$instance = $this->arguments instanceof Arguments ? $reflection->newInstanceArgs($this->arguments->inject($container)) : new $this->class();
return $this->postNewInstance($container, $instance);
}
/**
* @return class-string
*/
public function __toString(): string
{
return $this->class;
}
/**
* @param MethodArguments $params
*
* @throws ReflectionException
*/
public function newInstanceArgs(Container $container, array $params): object
{
$instance = (new ReflectionClass($this->class))->newInstanceArgs($params);
return $this->postNewInstance($container, $instance);
}
/**
* @param class-string $class
*/
public function weaveAspects(string $class, AopBind $bind): void
{
$this->class = $class;
$this->bind = new AspectBind($bind);
}
public function accept(VisitorInterface $visitor): void
{
$visitor->visitNewInstance(
$this->class,
$this->setterMethods,
$this->arguments,
$this->bind
);
}
private function postNewInstance(Container $container, object $instance): object
{
$this->enableAop($instance, $container);
// setter injection
($this->setterMethods)($instance, $container);
return $instance;
}
public function enableAop(object $instance, Container $container): void
{
if (! $this->bind instanceof AspectBind) {
return;
}
assert($instance instanceof WeavedInterface);
$instance->_setBindings($this->bind->inject($container)); // Ray.Aop ^2.18
}
}
================================================
FILE: src/di/NullDependency.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
/**
* @codeCoverageIgnore
*/
final class NullDependency implements DependencyInterface
{
/**
* {@inheritdoc}
*/
public function __toString(): string
{
return '';
}
/**
* {@inheritdoc}
*/
public function inject(Container $container): void
{
}
/**
* {@inheritdoc}
*/
public function register(array &$container, Bind $bind): void
{
$container[(string) $bind] = $bind->getBound();
}
/**
* {@inheritdoc}
*/
public function setScope($scope): void
{
}
}
================================================
FILE: src/di/NullModule.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
final class NullModule extends AbstractModule
{
protected function configure(): void
{
}
}
================================================
FILE: src/di/NullObjectDependency.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Koriym\NullObject\NullObject;
use ReflectionClass;
use function assert;
use function is_dir;
/**
* @codeCoverageIgnore
*/
final class NullObjectDependency implements DependencyInterface
{
/**
* @param class-string $interface
*/
public function __construct(private string $interface)
{
}
/**
* {@inheritdoc}
*/
public function __toString(): string
{
return '';
}
/**
* {@inheritdoc}
*/
public function inject(Container $container): null
{
return null;
}
/**
* {@inheritdoc}
*/
public function register(array &$container, Bind $bind): void
{
$container[(string) $bind] = $bind->getBound();
}
/**
* {@inheritdoc}
*/
public function setScope($scope): void
{
}
public function toNull(string $scriptDir): Dependency
{
assert(is_dir($scriptDir));
$nullObject = new NullObject();
$class = $nullObject->save($this->interface, $scriptDir);
return new Dependency(new NewInstance(new ReflectionClass($class), new SetterMethods([])));
}
}
================================================
FILE: src/di/ProviderInterface.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
/**
* @template T of mixed
*/
interface ProviderInterface
{
/**
* @return T
*/
public function get();
}
================================================
FILE: src/di/ProviderProvider.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Di\Di\Set;
/**
* @implements ProviderInterface<mixed>
* @template T of object
*/
final class ProviderProvider implements ProviderInterface
{
/** @param Set<T> $set */
public function __construct(private InjectorInterface $injector, private Set $set)
{
}
/** @return mixed */
public function get()
{
return $this->injector->getInstance($this->set->interface, $this->set->name);
}
}
================================================
FILE: src/di/ProviderSetModule.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
final class ProviderSetModule extends AbstractModule
{
protected function configure(): void
{
$this->bind(ProviderInterface::class)->toProvider(ProviderSetProvider::class);
}
}
================================================
FILE: src/di/ProviderSetProvider.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Di\Di\Set;
use Ray\Di\Exception\SetNotFound;
/**
* @implements ProviderInterface<mixed>
* @template T of object
*/
final class ProviderSetProvider implements ProviderInterface
{
public function __construct(private InjectionPointInterface $ip, private InjectorInterface $injector)
{
}
/** @phpstan-return ProviderProvider<object> */
public function get(): ProviderProvider
{
$param = $this->ip->getParameter();
$setAttribute = $param->getAttributes(Set::class);
if (! isset($setAttribute[0])) {
throw new SetNotFound((string) $this->ip->getParameter());
}
$set = $setAttribute[0]->newInstance();
return new ProviderProvider($this->injector, $set);
}
}
================================================
FILE: src/di/Scope.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
final class Scope
{
/**
* Singleton scope
*/
public const SINGLETON = 'Singleton';
/**
* Prototype scope
*/
public const PROTOTYPE = 'Prototype';
}
================================================
FILE: src/di/SetContextInterface.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
interface SetContextInterface
{
/**
* Set provider context
*
* @param string $context
*
* @return void
*/
public function setContext($context);
}
================================================
FILE: src/di/SetterMethod.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Exception;
use LogicException;
use Ray\Di\Exception\Unbound;
use ReflectionMethod;
use function call_user_func_array;
use function is_callable;
final class SetterMethod implements AcceptInterface
{
private readonly string $method;
private readonly Arguments $arguments;
/**
* Is optional binding ?
*/
private bool $isOptional = false;
public function __construct(ReflectionMethod $method, Name $name)
{
$this->method = $method->name;
$this->arguments = new Arguments($method, $name);
}
/**
* @param object $instance
*
* @throws Unbound
* @throws Exception
*/
public function __invoke($instance, Container $container): void
{
try {
$parameters = $this->arguments->inject($container);
} catch (Unbound $unbound) {
if ($this->isOptional) {
return;
}
throw $unbound;
}
$callable = [$instance, $this->method];
if (! is_callable($callable)) {
throw new LogicException(); // @codeCoverageIgnore
}
call_user_func_array($callable, $parameters);
}
public function setOptional(): void
{
$this->isOptional = true;
}
/** @inheritDoc */
public function accept(VisitorInterface $visitor): void
{
try {
$visitor->visitSetterMethod($this->method, $this->arguments);
} catch (Unbound $unbound) {
if ($this->isOptional) {
// Return when no dependency given and @Inject(optional=true) annotated to setter method.
return;
}
// Throw exception when no dependency given and @Inject(optional=false) annotated to setter method.
throw $unbound;
}
}
}
================================================
FILE: src/di/SetterMethods.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Exception;
/**
* @psalm-import-type SetterMethodsList from Types
*/
final class SetterMethods implements AcceptInterface
{
/**
* @param SetterMethodsList $setterMethods
*/
public function __construct(private array $setterMethods)
{
}
/**
* @throws Exception
*/
public function __invoke(object $instance, Container $container): void
{
foreach ($this->setterMethods as $setterMethod) {
($setterMethod)($instance, $container);
}
}
public function add(?SetterMethod $setterMethod = null): void
{
if (! $setterMethod instanceof SetterMethod) {
return;
}
$this->setterMethods[] = $setterMethod;
}
/** @inheritDoc */
public function accept(VisitorInterface $visitor): void
{
$visitor->visitSetterMethods($this->setterMethods);
}
}
================================================
FILE: src/di/SpyCompiler.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use LogicException;
use Ray\Aop\BindInterface;
use Ray\Aop\CompilerInterface;
use function array_keys;
use function implode;
use function method_exists;
use function sprintf;
/**
* @codeCoverageIgnore
*/
final class SpyCompiler implements CompilerInterface
{
/**
* {@inheritDoc}
*
* @phpstan-return never
*
* @psalm-suppress InvalidReturnType
* @template T of object
*/
public function newInstance(string $class, array $args, BindInterface $bind)
{
// never called
throw new LogicException('SpyCompiler::newInstance() should never be called');
}
/**
* Return "logging" class name
*
* Dummy classes are used for logging and don't really exist.
* So the code breaks the QA rules as shown below.
* NOTE: psalm-suppress is acceptable here for dummy/logging infrastructure
*
* @psalm-suppress MoreSpecificReturnType
* @psalm-suppress LessSpecificReturnStatement
*/
public function compile(string $class, BindInterface $bind): string
{
if ($this->hasNoBinding($class, $bind)) {
return $class;
}
return $class . $this->getInterceptors($bind); // @phpstan-ignore-line
}
/**
* @param class-string $class
*/
private function hasNoBinding(string $class, BindInterface $bind): bool
{
$hasMethod = $this->hasBoundMethod($class, $bind);
return ! $bind->getBindings() && ! $hasMethod;
}
/**
* @param class-string $class
*/
private function hasBoundMethod(string $class, BindInterface $bind): bool
{
$bindingMethods = array_keys($bind->getBindings());
$hasMethod = false;
foreach ($bindingMethods as $bindingMethod) {
if (method_exists($class, $bindingMethod)) {
$hasMethod = true;
}
}
return $hasMethod;
}
private function getInterceptors(BindInterface $bind): string
{
$bindings = $bind->getBindings();
if (! $bindings) {
return ''; // @codeCoverageIgnore
}
$log = ' (aop)';
foreach ($bindings as $method => $interceptors) {
/**
* @phpstan-var array<string> $interceptors
* @psalm-ignore-var
*/
$log .= sprintf(
' +%s(%s)',
$method,
implode(', ', $interceptors)
);
}
return $log;
}
}
================================================
FILE: src/di/Types.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Aop\MethodInterceptor;
use Ray\Aop\Pointcut;
/**
* Ray.Di Domain Types for Psalm
*
* This file contains Psalm type definitions for the Ray.Di dependency injection framework.
* These types enhance static analysis and provide better IDE support.
*
* Container and Registry Types
*
* @psalm-type DependencyContainer = array<non-empty-string, DependencyInterface>
* @psalm-type DependencyIndex = non-empty-string
* @psalm-type PointcutList array<int, Pointcut>
* @psalm-type BindingName = non-empty-string
* @psalm-type BindableInterface = class-string|''
* @psalm-type ConstructorNameMapping = array<non-empty-string, non-empty-string>
* @psalm-type ParameterNameMapping = array<string, string>
* @psalm-type NamedParameterString = non-empty-string
* @psalm-type ScriptDir = non-empty-string
*
* Enhanced Injection and Argument Types
* @psalm-type InjectableValue object|scalar|array<array-key, (object|scalar|null)>|null
* @psalm-type InjectionPointDefinition = array{0: string, 1: string, 2: bool}
* @psalm-type InjectionPointsList = list<InjectionPointDefinition>
* @psalm-type MethodArguments = list<mixed>
* @psalm-type ArgumentSerializationData = array{0: DependencyIndex, 1: bool, 2: string, 3: string, 4: string, 5: array{0: string, 1: string, 2: string}}
* @psalm-type UnboundTypeList = list<'bool'|'int'|'float'|'string'|'array'|'resource'|'callable'|'iterable'|'object'|'mixed'>
* @psalm-type QualifierList = array<object>
*
* Scope and Lifecycle Types
* @psalm-type ScopeType = Scope::SINGLETON|Scope::PROTOTYPE
* @psalm-type ProviderContext = string
*
* MultiBinding Types
* @psalm-type MultiBindingMap = array<string, non-empty-array<array-key, MultiBinding\LazyInterface>>
* @psalm-type LazyBindingList = non-empty-array<array-key, MultiBinding\LazyInterface>
*
* AOP and Aspect Types
* @psalm-type MethodInterceptorBindings array<non-empty-string, list<MethodInterceptor>>
* @psalm-type InterceptorClassList array<class-string<MethodInterceptor>>
* @psalm-type VisitorResult = object|array<array-key, mixed>|null
*
* Reflection and Metadata Types
* @psalm-type ReflectionMethodReference = array{0: string, 1: string, 2: string}
* @psalm-type DependencyMeta = string
*
* Exception and Error Types
* @psalm-type DiException = Exception\Unbound|Exception\Untargeted|Exception\NotFound|Exception\InvalidProvider|Exception\InvalidType
*
* Annotation Types
* @psalm-type AnnotationType = Di\Named|Di\Inject|Di\Qualifier|Di\PostConstruct|Di\Assisted|Di\Set<object>
* @psalm-type DependencyImplementation = Dependency|DependencyProvider|Instance|NullDependency|NullObjectDependency
* @psalm-type LazyImplementation = MultiBinding\LazyInstance<mixed>|MultiBinding\LazyProvider<ProviderInterface<mixed>>|MultiBinding\LazyTo<object>
*
* Core Component Types
* @psalm-type SetterMethodsList = array<SetterMethod>
* @psalm-type ArgumentsList = array<Argument>
*
* Domain-Specific Array Types
* @psalm-type ModuleList = non-empty-array<AbstractModule>
* @psalm-type NamedArguments = array<string, InjectableValue>
*/
final class Types
{
}
================================================
FILE: src/di/Untarget.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Aop\ReflectionClass;
final class Untarget
{
/**
* @phpstan-var ReflectionClass<object>
* @psalm-var ReflectionClass
*/
private readonly ReflectionClass $class;
private string $scope = Scope::PROTOTYPE;
/**
* @param class-string $class
*/
public function __construct(string $class)
{
$this->class = new ReflectionClass($class);
}
/**
* Bind untargeted binding
*/
public function __invoke(Container $container, Bind $bind): void
{
$bound = (new DependencyFactory())->newAnnotatedDependency($this->class);
$bound->setScope($this->scope);
$bind->setBound($bound);
$container->add($bind);
}
public function setScope(string $scope): void
{
$this->scope = $scope;
}
}
================================================
FILE: src/di/VisitorInterface.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Aop\Bind as AopBind;
use ReflectionParameter;
/**
* Visits a Dependency
*
* @psalm-import-type SetterMethodsList from Types
* @psalm-import-type ArgumentsList from Types
*/
interface VisitorInterface
{
/**
* Visits a Dependency
*
* @return mixed|void
*/
public function visitDependency(NewInstance $newInstance, ?string $postConstruct, bool $isSingleton);
/**
* Visits a Provider
*
* @return mixed|void
*/
public function visitProvider(Dependency $dependency, string $context, bool $isSingleton);
/**
* Visits an Instance
*
* @param mixed $value
*
* @return mixed|void
*/
public function visitInstance($value);
/**
* Visits an AspectBind
*
* @return mixed|void
*/
public function visitAspectBind(AopBind $aopBind);
/**
* Visits a New Instance
*
* @return mixed|void
*/
public function visitNewInstance(
string $class,
SetterMethods $setterMethods,
?Arguments $arguments,
?AspectBind $bind
);
/**
* Visits Setter Methods
*
* @param SetterMethodsList $setterMethods
*
* @return mixed|void
*/
public function visitSetterMethods(array $setterMethods);
/**
* Visits a Setter Method
*
* @return mixed|void
*/
public function visitSetterMethod(string $method, Arguments $arguments);
/**
* Visits Arguments
*
* @param ArgumentsList $arguments
*
* @return mixed|void
*/
public function visitArguments(array $arguments);
/**
* Visits an Argument
*
* @param mixed $defaultValue
*
* @return mixed|void
*/
public function visitArgument(
string $index,
bool $isDefaultAvailable,
$defaultValue,
ReflectionParameter $parameter
);
}
================================================
FILE: src-deprecated/di/BcParameterQualifier.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Di\Di\InjectInterface;
use Ray\Di\Di\Qualifier;
use ReflectionAttribute;
use ReflectionClass;
use ReflectionMethod;
use function count;
/**
* Backward compatible parameter qualifier for single-parameter methods
*
* Automatically applies method-level Qualifier attributes to parameters when:
* - Method has exactly one parameter
* - Parameter has no explicit qualifier
* - For constructors: Method has a Qualifier attribute (InjectInterface is implicit)
* - For setters: Method has an attribute implementing both InjectInterface and Qualifier
*
* This behavior is deprecated for the following reasons:
* - Violates Single Responsibility Principle (one attribute serving dual purposes)
* - Creates fragility when refactoring (adding parameters changes behavior)
* - Reduces code clarity (implicit rather than explicit)
*
* @deprecated Use explicit separation: #[Inject] at method level, Qualifier at parameter level
*
* Recommended migration:
* OLD (implicit):
* #[FakeLogDbInject]
* public function setDb(ExtendedPdoInterface $pdo) { }
*
* NEW (explicit):
* #[Inject]
* public function setDb(#[FakeLogDb] ExtendedPdoInterface $pdo) { }
*
* @internal
*/
final class BcParameterQualifier
{
/**
* Get parameter qualifier names from method-level attribute if applicable
*
* Returns parameter name mapping if:
* 1. Method has exactly one parameter
* 2. Parameter has no qualifier attribute
* 3. For setters: Method has an attribute implementing both InjectInterface and Qualifier
* 4. For constructors: Method has a Qualifier attribute (InjectInterface is implicit)
*
* @param ReflectionMethod $method The method to analyze
*
* @return array<string, string> Parameter name to qualifier mapping (empty if not applicable)
*/
public static function getNames(ReflectionMethod $method): array
{
$params = $method->getParameters();
// Only for single-parameter methods
if (count($params) !== 1) {
return [];
}
$qualifier = self::getQualifier($method);
if ($qualifier === '') {
return [];
}
return [$params[0]->name => $qualifier];
}
/**
* Get parameter qualifier from method-level attribute if applicable
*
* Returns the qualifier name if:
* 1. Method has exactly one parameter
* 2. Parameter has no qualifier attribute
* 3. For setters: Method has an attribute implementing both InjectInterface and Qualifier
* 4. For constructors: Method has a Qualifier attribute (InjectInterface is implicit)
*
* @param ReflectionMethod $method The method to analyze
*
* @return string The qualifier class name, or empty string if not applicable
*/
private static function getQualifier(ReflectionMethod $method): string
{
$params = $method->getParameters();
// Only for single-parameter methods
if (count($params) !== 1) {
return '';
}
$param = $params[0];
// Check if parameter already has a qualifier
if (self::hasParameterQualifier($param->getAttributes())) {
return '';
}
$isConstructor = $method->name === '__construct';
// Check method-level attributes for Qualifier
$methodAttributes = $method->getAttributes();
foreach ($methodAttributes as $attr) {
$instance = $attr->newInstance();
$attrClass = new ReflectionClass($attr->getName());
$qualifierAttr = $attrClass->getAttributes(Qualifier::class);
// Skip if not a Qualifier
if ($qualifierAttr === []) {
continue;
}
// For constructors: Qualifier alone is sufficient (InjectInterface is implicit)
if ($isConstructor) {
return $attr->getName();
}
// For setters: Must also implement InjectInterface
if ($instance instanceof InjectInterface) {
return $attr->getName();
}
}
return '';
}
/**
* Check if parameter already has a qualifier attribute
*
* @param array<ReflectionAttribute> $attributes
*/
private static function hasParameterQualifier(array $attributes): bool
{
foreach ($attributes as $attr) {
$attrClass = new ReflectionClass($attr->getName());
// Check for Qualifier marker
if ($attrClass->getAttributes(Qualifier::class) !== []) {
return true;
}
}
return false;
}
}
================================================
FILE: src-deprecated/di/BcStringParser.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use function explode;
use function substr;
use function trim;
/**
* Backward compatible string format parser for toConstructor() method
*
* Parses "key=value,key=value" string format for backward compatibility.
* This format is deprecated. Use parameter-level attributes or array format instead.
*
* @deprecated Use parameter-level attributes (#[Named('name')]) or array format (['param' => 'name'])
*
* @internal
*/
final class BcStringParser
{
/**
* Parse "key=value,key=value" format
*
* @return array<string, string>
*
* @psalm-pure
*/
public static function parse(string $name): array
{
$names = [];
$keyValues = explode(',', $name);
foreach ($keyValues as $keyValue) {
$exploded = explode('=', $keyValue, 2);
if (isset($exploded[1])) {
[$key, $value] = $exploded;
if (isset($key[0]) && $key[0] === '$') {
$key = substr($key, 1);
}
$trimmedKey = trim($key);
if ($trimmedKey === '') {
continue;
}
$names[$trimmedKey] = trim($value);
}
}
return $names;
}
}
================================================
FILE: src-deprecated/di/EmptyModule.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
/**
* @deprecated User NullModule instead
*/
class EmptyModule extends AbstractModule
{
/**
* {@inheritdoc}
*/
protected function configure() : void
{
}
}
================================================
FILE: src-deprecated/di/NullCache.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Doctrine\Common\Cache\CacheProvider;
/**
* @psalm-suppress DeprecatedInterface
* @deprecated
*/
final class NullCache extends CacheProvider
{
/**
* {@inheritDoc}
*/
protected function doFetch($id)
{
return false;
}
/**
* {@inheritDoc}
*/
protected function doContains($id)
{
return false;
}
/**
* {@inheritDoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
return true;
}
/**
* {@inheritDoc}
*/
protected function doDelete($id)
{
return true;
}
/**
* {@inheritDoc}
*/
protected function doFlush()
{
return true;
}
/**
* {@inheritDoc}
*/
protected function doGetStats()
{
return [];
}
}
================================================
FILE: src-deprecated/di/Provider.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
/**
* @deprecated User ProviderInterface instead
*/
interface Provider extends ProviderInterface
{
}
================================================
FILE: tests/bootstrap.php
================================================
<?php
declare(strict_types=1);
putenv('TMPDIR=' . __DIR__ . '/tmp');
require_once dirname(__DIR__) . '/vendor/autoload.php';
$deleteFiles = static function (string $path) use (&$deleteFiles): void {
foreach (array_filter((array) glob($path . '/*')) as $file) {
is_dir($file) ? $deleteFiles($file) : unlink($file);
@rmdir($file);
}
};
$deleteFiles(__DIR__ . '/tmp');
$deleteFiles(__DIR__ . '/compiler/tmp');
================================================
FILE: tests/di/AnnotatedClassTest.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use LogicException;
use PHPUnit\Framework\TestCase;
use Ray\Aop\ReflectionClass;
class AnnotatedClassTest extends TestCase
{
/** @var AnnotatedClass */
protected $annotatedClass;
protected function setUp(): void
{
parent::setUp();
$this->annotatedClass = new AnnotatedClass();
}
public function testInvoke(): void
{
$newInstance = $this->annotatedClass->getNewInstance(new ReflectionClass(FakeCar::class)); // @phpstan-ignore-line
$this->assertInstanceOf(NewInstance::class, $newInstance);
$container = new Container();
(new Bind($container, FakeTyreInterface::class))->to(FakeTyre::class);
(new Bind($container, FakeEngineInterface::class))->to(FakeEngine::class);
(new Bind($container, FakeHandleInterface::class))->toProvider(FakeHandleProvider::class);
(new Bind($container, FakeMirrorInterface::class))->annotatedWith('right')->to(FakeMirrorRight::class);
(new Bind($container, FakeMirrorInterface::class))->annotatedWith('left')->to(FakeMirrorRight::class);
(new Bind($container, FakeGearStickInterface::class))->annotatedWith(FakeGearStickInject::class)->toProvider(FakeGearStickProvider::class);
$car = $newInstance($container);
if (! $car instanceof FakeCar) {
throw new LogicException();
}
$this->assertInstanceOf(FakeCar::class, $car);
$this->assertInstanceOf(FakeTyre::class, $car->frontTyre);
$this->assertInstanceOf(FakeTyre::class, $car->rearTyre);
$this->assertInstanceOf(FakeLeatherGearStick::class, $car->gearStick);
$this->assertNull($car->hardtop);
}
/**
* @phpstan-param class-string $class
*
* @dataProvider classProvider
*/
public function testAnnotatedByAnnotation(string $class): void
{
$newInstance = $this->annotatedClass->getNewInstance(new ReflectionClass($class));
$container = new Container();
(new Bind($container, FakeMirrorInterface::class))->annotatedWith(FakeLeft::class)->to(FakeMirrorLeft::class);
(new Bind($container, FakeMirrorInterface::class))->annotatedWith(FakeRight::class)->to(FakeMirrorRight::class);
$handleBar = $newInstance($container);
if (! $handleBar instanceof FakeHandleBar && ! $handleBar instanceof FakeHandleBarQualifier) {
throw new LogicException();
}
$this->assertInstanceOf(FakeMirrorLeft::class, $handleBar->leftMirror);
$this->assertInstanceOf(FakeMirrorRight::class, $handleBar->rightMirror);
}
/**
* @return array<array<class-string>>
*/
public function classProvider(): array
{
return [
[FakeHandleBar::class],
[FakeHandleBarQualifier::class],
];
}
}
================================================
FILE: tests/di/ArgumentTest.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use PHPUnit\Framework\TestCase;
use ReflectionMethod;
use ReflectionParameter;
use function assert;
use function serialize;
use function unserialize;
class ArgumentTest extends TestCase
{
/** @var Argument */
protected $argument;
protected function setUp(): void
{
$this->argument = new Argument(new ReflectionParameter([FakeCar::class, '__construct'], 'engine'), Name::ANY);
}
public function testToString(): void
{
$this->assertSame('Ray\Di\FakeEngineInterface-' . Name::ANY, (string) $this->argument);
}
public function testToStringScalar(): void
{
$argument = new Argument(new ReflectionParameter([FakeInternalTypes::class, 'stringId'], 'id'), Name::ANY);
$this->assertSame('-' . Name::ANY, (string) $argument);
}
public function testSerializable(): void
{
$argument = unserialize(serialize(new Argument(new ReflectionParameter([FakeInternalTypes::class, 'stringId'], 'id'), Name::ANY)));
assert($argument instanceof Argument);
$class = $argument->get()->getDeclaringFunction();
$this->assertInstanceOf(ReflectionMethod::class, $class);
}
}
================================================
FILE: tests/di/ArgumentsTest.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use PHPUnit\Framework\TestCase;
use ReflectionMethod;
use ReflectionParameter;
use function spl_object_hash;
class ArgumentsTest extends TestCase
{
/** @var Arguments */
protected $arguments;
protected function setUp(): void
{
$this->arguments = new Arguments(new ReflectionMethod(FakeCar::class, 'setTires'), new Name(Name::ANY));
}
public function testInject(): void
{
$container = (new FakeCarModule())->getContainer();
$parameters = $this->arguments->inject($container);
$this->assertInstanceOf(FakeTyre::class, $parameters[0]);
$this->assertInstanceOf(FakeTyre::class, $parameters[1]);
$param0 = $parameters[0];
$this->assertNotSame(spl_object_hash($param0), $parameters[1]);
}
public function testParameterDefaultValue(): void
{
$defaultValue = (new ReflectionParameter([FakeHandleProvider::class, '__construct'], 'logo'))->getDefaultValue();
$emptyContainer = new Container();
$parameters = new Arguments(new ReflectionMethod(FakeHandleProvider::class, '__construct'), new Name(Name::ANY));
$parametersValue = $parameters->inject($emptyContainer);
$this->assertSame($defaultValue, $parametersValue[0]);
}
}
================================================
FILE: tests/di/AssistedTest.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use PHPUnit\Framework\TestCase;
use Ray\Di\Exception\MethodInvocationNotAvailable;
class AssistedTest extends TestCase
{
/** @var InjectorInterface */
private $injector;
protected function setUp(): void
{
$this->injector = new Injector(new FakeToBindModule());
}
public function testAssisted(): void
{
$consumer = $this->injector->getInstance(FakeAssistedConsumer::class);
$assistedDependency = $consumer->assistOne('a', 'b');
$expected = FakeRobot::class;
$this->assertInstanceOf($expected, $assistedDependency);
}
public function testAssistedWithName(): void
{
$this->injector = new Injector(new FakeInstanceBindModule());
$consumer = $this->injector->getInstance(FakeAssistedConsumer::class);
$assistedDependency = $consumer->assistWithName('a7');
$expected = 1;
$this->assertSame($expected, $assistedDependency);
}
public function testAssistedAnyWithName(): void
{
$injector = new Injector(new FakeToBindModule(new FakeInstanceBindModule()));
$consumer = $injector->getInstance(FakeAssistedConsumer::class);
[$assistedDependency1, $assistedDependency2] = $consumer->assistAny();
$expected1 = 1;
$this->assertSame($expected1, $assistedDependency1);
$this->assertInstanceOf(FakeRobot::class, $assistedDependency2);
}
public function testAssistedMethodInvocation(): void
{
$assistedConsumer = (new Injector(new FakeAssistedDbModule()))->getInstance(FakeAssistedParamsConsumer::class);
[$id, $db] = $assistedConsumer->getUser(1);
/** @var FakeAbstractDb $db */
$this->assertSame(1, $id);
$this->assertSame(1, $db->dbId);
}
public function testAssistedMethodInvocationNotAvailable(): void
{
$this->expectException(MethodInvocationNotAvailable::class);
$assistedDbProvider = (new Injector(new FakeAssistedDbModule()))->getInstance(FakeAssistedDbProvider::class);
$assistedDbProvider->get();
}
public function testAssistedCustomInject(): void
{
$assistedConsumer = (new Injector(new FakeAssistedDbModule()))->getInstance(FakeAssistedParamsConsumer::class);
[$id] = $assistedConsumer->getUser(1);
$this->assertSame(1, $id);
}
}
================================================
FILE: tests/di/BcParameterQualifierIntegrationTest.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use PHPUnit\Framework\TestCase;
class BcParameterQualifierIntegrationTest extends TestCase
{
public function testBcParameterQualifierWorks(): void
{
$injector = new Injector(new FakeBcParameterQualifierModule());
/** @psalm-suppress DeprecatedClass */
$instance = $injector->getInstance(FakeClassWithBcParameterQualifier::class);
// The setGearStick method uses #[FakeInjectOne] at method level only
// BcParameterQualifier should apply it to the parameter
$this->assertInstanceOf(FakeLeatherGearStick::class, $instance->gearStick);
}
}
================================================
FILE: tests/di/BcParameterQualifierTest.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use PHPUnit\Framework\TestCase;
use Ray\Di\Annotation\FakeInjectOne;
use Ray\Di\Annotation\FakeQualifierOnly;
use ReflectionMethod;
class BcParameterQualifierTest extends TestCase
{
public function testGetNamesFromMethodLevelAttribute(): void
{
$method = new ReflectionMethod(FakeBcParameterQualifierClass::class, 'setSingleParam');
/** @psalm-suppress DeprecatedClass */
$names = BcParameterQualifier::getNames($method);
$this->assertSame(['param' => FakeInjectOne::class], $names);
}
public function testNoNamesForMultipleParameters(): void
{
$method = new ReflectionMethod(FakeBcParameterQualifierClass::class, 'setMultipleParams');
/** @psalm-suppress DeprecatedClass */
$names = BcParameterQualifier::getNames($method);
$this->assertSame([], $names);
}
public function testNoNamesWhenParameterHasQualifier(): void
{
$method = new ReflectionMethod(FakeBcParameterQualifierClass::class, 'setSingleParamWithQualifier');
/** @psalm-suppress DeprecatedClass */
$names = BcParameterQualifier::getNames($method);
$this->assertSame([], $names);
}
public function testNoNamesForNonQualifierAttribute(): void
{
$method = new ReflectionMethod(FakeBcParameterQualifierClass::class, 'setSingleParamWithInjectOnly');
/** @psalm-suppress DeprecatedClass */
$names = BcParameterQualifier::getNames($method);
$this->assertSame([], $names);
}
public function testNoNamesForMethodWithoutInjectInterface(): void
{
$method = new ReflectionMethod(FakeBcParameterQualifierClass::class, 'setSingleParamNoInject');
/** @psalm-suppress DeprecatedClass */
$names = BcParameterQualifier::getNames($method);
$this->assertSame([], $names);
}
public function testNamesForTargetMethodOnly(): void
{
// FakeGearStickInject has TARGET_METHOD only
// BC parameter qualifier now supports TARGET_METHOD-only attributes for backward compatibility
$method = new ReflectionMethod(FakeBcParameterQualifierClass::class, 'setSingleParamMethodOnly');
/** @psalm-suppress DeprecatedClass */
$names = BcParameterQualifier::getNames($method);
$this->assertSame(['param' => FakeGearStickInject::class], $names);
}
public function testConstructorWithQualifierOnly(): void
{
// Constructor with Qualifier-only attribute (no InjectInterface)
// BC parameter qualifier should apply for constructors (InjectInterface is implicit)
$method = new ReflectionMethod(FakeBcConstructorQualifierClass::class, '__construct');
/** @psalm-suppress DeprecatedClass */
$names = BcParameterQualifier::getNames($method);
$this->assertSame(['param' => FakeQualifierOnly::class], $names);
}
}
================================================
FILE: tests/di/BcStringParserTest.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use PHPUnit\Framework\TestCase;
class BcStringParserTest extends TestCase
{
public function testParseStringFormat(): void
{
$result = BcStringParser::parse('engine=engine_name,var=var_name');
$expected = ['engine' => 'engine_name', 'var' => 'var_name'];
$this->assertSame($expected, $result);
}
public function testParseStringFormatWithSpaces(): void
{
$result = BcStringParser::parse('engine=engine_name, var=var_name');
$expected = ['engine' => 'engine_name', 'var' => 'var_name'];
$this->assertSame($expected, $result);
}
public function testParseStringFormatWithDollarPrefix(): void
{
$result = BcStringParser::parse('$engine=engine_name,$var=var_name');
$expected = ['engine' => 'engine_name', 'var' => 'var_name'];
$this->assertSame($expected, $result);
}
}
================================================
FILE: tests/di/BindTest.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use PHPUnit\Framework\TestCase;
use Ray\Di\Exception\InvalidProvider;
use Ray\Di\Exception\InvalidType;
use Ray\Di\Exception\NotFound;
use function assert;
use function property_exists;
use function spl_object_hash;
class BindTest extends TestCase
{
/** @var Bind */
private $bind;
protected function setUp(): void
{
parent::setUp();
$this->bind = new Bind(new Container(), FakeTyreInterface::class);
}
public function testGetBound(): void
{
$this->bind->to(FakeTyre::class);
$bound = $this->bind->getBound();
$this->assertInstanceOf(Dependency::class, $bound);
}
public function testToString(): void
{
$this->assertSame('Ray\Di\FakeTyreInterface-' . Name::ANY, (string) $this->bind);
}
public function testInvalidToTest(): void
{
$this->expectException(NotFound::class);
$this->bind->to('invalid-class'); // @phpstan-ignore-line
}
public function testInvalidToProviderTest(): void
{
$this->expectException(NotFound::class);
$this->bind->toProvider('invalid-class'); // @phpstan-ignore-line
}
public function testInValidInterfaceBinding(): void
{
$this->expectException(NotFound::class);
new Bind(new Container(), 'invalid-interface');
}
public function testUntargetedBind(): void
{
$container = new Container();
$bind = new Bind($container, FakeEngine::class);
unset($bind);
$container = $container->getContainer();
$this->assertArrayHasKey(FakeEngine::class . '-' . Name::ANY, $container);
}
public function testUntargetedBindSingleton(): void
{
$container = new Container();
$bind = (new Bind($container, FakeEngine::class))->in(Scope::SINGLETON);
unset($bind);
$dependency1 = $container->getInstance(FakeEngine::class, Name::ANY);
$dependency2 = $container->getInstance(FakeEngine::class, Name::ANY);
$this->assertSame(spl_object_hash($dependency1), spl_object_hash($dependency2));
}
/**
* @return array<int, array<int, array<string, string>>>
*/
public function nameProvider(): array
{
return [
[['tmpDir' => 'tmp_dir', 'leg' => 'left']],
];
}
/**
* @param array<string, string>|string $name
*
* @dataProvider nameProvider
*/
public function testToConstructor($name): void
{
$container = new Container();
$container->add((new Bind($container, ''))->annotatedWith('tmp_dir')->toInstance('/tmp'));
$container->add((new Bind($container, FakeLegInterface::class))->annotatedWith('left')->to(FakeLeftLeg::class));
$container->add((new Bind($container, FakeRobotInterface::class))->toConstructor(FakeToConstructorRobot::class, $name));
$instance = $container->getInstance(FakeRobotInterface::class, Name::ANY);
assert($instance instanceof FakeToConstructorRobot);
$this->assertInstanceOf(FakeLeftLeg::class, $instance->leg);
$this->assertSame('/tmp', $instance->tmpDir);
}
public function testToConstructorWithMethodInjection(): void
{
$container = new Container();
$container->add((new Bind($container, ''))->annotatedWith('tmp_dir')->toInstance('/tmp'));
$container->add((new Bind($container, FakeLegInterface::class))->annotatedWith('left')->to(FakeLeftLeg::class));
$container->add((new Bind($container, FakeEngineInterface::class))->to(FakeEngine::class));
$container->add(
(new Bind($container, FakeRobotInterface::class))->toConstructor(
FakeToConstructorRobot::class,
['tmpDir' => 'tmp_dir', 'leg' => 'left'],
(new InjectionPoints())->addMethod('setEngine')
)
);
$instance = $container->getInstance(FakeRobotInterface::class, Name::ANY);
assert($instance instanceof FakeToConstructorRobot);
$this->assertInstanceOf(FakeEngine::class, $instance->engine);
}
public function testToValidation(): void
{
$this->expectException(InvalidType::class);
(new Bind(new Container(), FakeHandleInterface::class))->to(FakeEngine::class);
}
public function testToProvider(): void
{
$this->expectException(InvalidProvider::class);
(new Bind(new Container(), FakeHandleInterface::class))->toProvider(FakeEngine::class);
}
public function testBindProviderAsProvider(): void
{
$container = new Container();
(new Bind($container, ProviderInterface::class))->annotatedWith('handle')->to(FakeHandleProvider::class);
$instance = $container->getInstance(ProviderInterface::class, 'handle');
$this->assertInstanceOf(FakeHandleProvider::class, $instance);
}
public function testBindProviderAsProviderInSingleton(): void
{
$container = new Container();
(new Bind($container, ProviderInterface::class))->annotatedWith('handle')->to(FakeHandleProvider::class)->in(Scope::SINGLETON);
$instance1 = $container->getInstance(ProviderInterface::class, 'handle');
$instance2 = $container->getInstance(ProviderInterface::class, 'handle');
$this->assertSame(spl_object_hash($instance1), spl_object_hash($instance2));
}
public function testProviderContext(): void
{
$container = new Container();
(new Bind($container, ProviderInterface::class))->toProvider(FakeContextualProvider::class, 'context_string');
$instance = $container->getInstance(ProviderInterface::class, Name::ANY);
assert(property_exists($instance, 'context'));
$this->assertSame('context_string', $instance->context);
}
}
================================================
FILE: tests/di/ContainerTest.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use BadMethodCallException;
use PHPUnit\Framework\TestCase;
use Ray\Aop\Compiler;
use Ray\Aop\Matcher;
use Ray\Aop\Pointcut;
use Ray\Di\Exception\Unbound;
use Throwable;
use function assert;
use function get_class;
use function sys_get_temp_dir;
class ContainerTest extends TestCase
{
/** @var Container */
private $container;
/** @var FakeEngine */
private $engine;
protected function setUp(): void
{
parent::setUp();
$this->container = new Container();
$this->engine = new FakeEngine();
(new Bind($this->container, FakeEngineInterface::class))->toInstance($this->engine);
}
public function testGetDependency(): void
{
$dependencyIndex = FakeEngineInterface::class . '-' . Name::ANY;
$instance = $this->container->getDependency($dependencyIndex);
$this->assertInstanceOf(FakeEngine::class, $instance);
$this->assertSame($this->engine, $instance);
}
public function testClassGetDependency(): void
{
(new Bind($this->container, FakeEngine::class))->toInstance($this->engine);
$dependencyIndex = FakeEngine::class . '-' . Name::ANY;
$instance = $this->container->getDependency($dependencyIndex);
$this->assertInstanceOf(FakeEngine::class, $instance);
$this->assertSame($this->engine, $instance);
}
public function testProviderGetDependency(): void
{
(new Bind($this->container, FakeEngine::class))->toProvider(FakeEngineProvider::class);
$dependencyIndex = FakeEngine::class . '-' . Name::ANY;
$instance = $this->container->getDependency($dependencyIndex);
$this->assertInstanceOf(FakeEngine::class, $instance);
}
public function testGetInstance(): void
{
$instance = $this->container->getInstance(FakeEngineInterface::class, Name::ANY);
$this->assertInstanceOf(FakeEngine::class, $instance);
$this->assertSame($this->engine, $instance);
}
public function testClassGetInstance(): void
{
(new Bind($this->container, FakeEngine::class))->toInstance($this->engine);
$instance = $this->container->getInstance(FakeEngine::class, Name::ANY);
$this->assertInstanceOf(FakeEngine::class, $instance);
$this->assertSame($this->engine, $instance);
}
public function testProviderGetInstance(): void
{
(new Bind($this->container, FakeEngine::class))->toProvider(FakeEngineProvider::class);
$instance = $this->container->getInstance(FakeEngine::class, Name::ANY);
$this->assertInstanceOf(FakeEngine::class, $instance);
}
public function testGetContainer(): void
{
$array = $this->container->getContainer();
$dependencyIndex = FakeEngineInterface::class . '-' . Name::ANY;
$this->assertArrayHasKey($dependencyIndex, $array);
}
public function testClassGetContainer(): void
{
(new Bind($this->container, FakeEngine::class))->toInstance($this->engine);
$array = $this->container->getContainer();
$dependencyIndex = FakeEngine::class . '-' . Name::ANY;
$this->assertArrayHasKey($dependencyIndex, $array);
}
public function testMerge(): void
{
$extraContainer = new Container();
$bind = (new Bind($this->container, FakeRobotInterface::class))->to(FakeRobot::class);
$this->container->add($bind);
$this->container->merge($extraContainer);
$array = $this->container->getContainer();
$this->assertArrayHasKey(FakeEngineInterface::class . '-' . Name::ANY, $array);
$this->assertArrayHasKey(FakeRobotInterface::class . '-' . Name::ANY, $array);
}
public function testMergePointcuts(): void
{
$extraContainer = new Container();
$pointcut1 = new Pointcut((new Matcher())->any(), (new Matcher())->any(), [FakeDoubleInterceptor::class]);
$pointcut2 = new Pointcut((new Matcher())->any(), (new Matcher())->any(), [FakeDoubleInterceptor::class]);
$this->container->addPointcut($pointcut1);
$extraContainer->addPointcut($pointcut2);
$this->container->merge($extraContainer);
$array = [];
foreach ($this->container->getPointcuts() as $pointcut) {
$array[] = $pointcut->interceptors[0];
}
$this->assertContains(FakeDoubleInterceptor::class, $array);
}
public function testMove(): void
{
$newName = 'new';
$this->container->move(FakeEngineInterface::class, Name::ANY, FakeEngineInterface::class, $newName);
$dependencyIndex = FakeEngineInterface::class . '-' . $newName;
$instance = $this->container->getDependency($dependencyIndex);
$this->assertInstanceOf(FakeEngine::class, $instance);
}
public function testMoveUnbound(): void
{
$this->expectException(Unbound::class);
$this->container->move(FakeEngineInterface::class, 'invalid', FakeEngineInterface::class, 'new');
}
public function testAbstractClassUnbound(): void
{
try {
$this->container->getInstance('_INVALID_INTERFACE_', Name::ANY); // @phpstan-ignore-line
} catch (Throwable $e) {
$this->assertSame(Unbound::class, get_class($e));
}
}
public function testAnnotateConstant(): void
{
$container = new Container();
//FakeConstantInterface
(new Bind($container, ''))->annotatedWith(FakeConstant::class)->toInstance('kuma');
(new Bind($container, FakeConstantConsumer::class));
$instance = $container->getInstance(FakeConstantConsumer::class, Name::ANY);
$this->assertSame('kuma', $instance->constantByConstruct);
$this->assertSame('kuma', $instance->constantBySetter);
$this->assertSame('kuma', $instance->setterConstantWithoutVarName);
$this->assertSame('default_construct', $instance->defaultByConstruct);
$this->assertSame('default_setter', $instance->defaultBySetter);
}
public function testBadMethodCall(): void
{
$this->expectException(BadMethodCallException::class);
$container = new Container();
//FakeConstantInterface
(new Bind($container, FakeEngineInterface::class))->toInstance(new FakeEngine());
$container->getInstanceWithArgs(FakeEngineInterface::class, []);
}
/**
* @covers \Ray\Di\Container::getInstanceWithArgs
*/
public function testUnbound(): void
{
$this->expectException(Unbound::class);
(new Container())->getInstanceWithArgs(FakeEngineInterface::class, []);
}
public function testWeaveAspectsWithEmptyPointcuts(): void
{
$container = new Container();
(new Bind($container, FakeEngine::class));
// Should work fine even when no pointcuts are defined
$tmpDir = sys_get_temp_dir();
assert($tmpDir !== '');
$container->weaveAspects(new Compiler($tmpDir));
$instance = $container->getInstance(FakeEngine::class);
$this->assertInstanceOf(FakeEngine::class, $instance);
}
}
================================================
FILE: tests/di/ContextualProviderTest.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use PHPUnit\Framework\TestCase;
class ContextualProviderTest extends TestCase
{
public function testContextualProviderInjection(): void
{
$robot = (new Injector(new FakeContextualModule('main')))->getInstance(FakeRobotInterface::class);
/** @var FakeContextualRobot $robot */
$this->assertSame($robot->context, 'main');
}
}
================================================
FILE: tests/di/DependencyTest.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use PHPUnit\Framework\TestCase;
use Ray\Aop\Compiler;
use Ray\Aop\Matcher;
use Ray\Aop\Pointcut;
use Ray\Aop\WeavedInterface;
use ReflectionClass;
use ReflectionMethod;
use function assert;
use function is_object;
use function property_exists;
use function spl_object_hash;
class DependencyTest extends TestCase
{
/** @var Dependency */
private $dependency;
protected function setUp(): void
{
/** @var ReflectionClass<object> $class */
$class = new ReflectionClass(FakeCar::class);
$setters = [];
$name = new Name(Name::ANY);
$setters[] = new SetterMethod(new ReflectionMethod(FakeCar::class, 'setTires'), $name);
$setters[] = new SetterMethod(new ReflectionMethod(FakeCar::class, 'setHardtop'), $name);
$setterMethods = new SetterMethods($setters);
$newInstance = new NewInstance($class, $setterMethods);
$this->dependency = new Dependency($newInstance, new ReflectionMethod(FakeCar::class, 'postConstruct'));
}
/**
* @return Container[][]
* @psalm-return array{0: array{0: Container}}
*/
public function containerProvider(): array
{
$container = new Container();
(new Bind($container, FakeTyreInterface::class))->to(FakeTyre::class);
(new Bind($container, FakeEngineInterface::class))->to(FakeEngine::class);
(new Bind($container, FakeHardtopInterface::class))->to(FakeHardtop::class);
return [[$container]];
}
/**
* @dataProvider containerProvider
*/
public function testInject(Container $container): void
{
$car = $this->dependency->inject($container);
/** @var FakeCar $car */
$this->assertInstanceOf(FakeCar::class, $car);
}
/**
* @dataProvider containerProvider
*/
public function testSetterInjection(Container $container): void
{
$car = $this->dependency->inject($container);
/** @var FakeCar $car */
$this->assertInstanceOf(FakeCar::class, $car);
$this->assertInstanceOf(FakeTyre::class, $car->frontTyre);
}
/**
* @dataProvider containerProvider
*/
public function testPostConstruct(Container $container): void
{
$car = $this->dependency->inject($container);
/** @var FakeCar $car */
$this->assertTrue($car->isConstructed);
}
/**
* @dataProvider containerProvider
*/
public function testPrototype(Container $container): void
{
$this->dependency->setScope(Scope::PROTOTYPE);
$car1 = $this->dependency->inject($container);
$car2 = $this->dependency->inject($container);
assert(is_object($car1) && is_object($car2));
$this->assertNotSame(spl_object_hash($car1), spl_object_hash($car2));
}
/**
* @dataProvider containerProvider
*/
public function testSingleton(Container $container): void
{
$this->dependency->setScope(Scope::SINGLETON);
$car1 = $this->dependency->inject($container);
$car2 = $this->dependency->inject($container);
assert(is_object($car1) && is_object($car2));
$this->assertSame(spl_object_hash($car1), spl_object_hash($car2));
}
public function testInjectInterceptor(): void
{
/** @var ReflectionClass<object> $class */
$class = new ReflectionClass(FakeAop::class);
$dependency = new Dependency(new NewInstance($class, new SetterMethods([])));
$pointcut = new Pointcut((new Matcher())->any(), (new Matcher())->any(), [FakeDoubleInterceptor::class]);
$dependency->weaveAspects(new Compiler(__DIR__ . '/tmp'), [$pointcut]);
$container = new Container();
$container->add((new Bind($container, FakeDoubleInterceptor::class))->to(FakeDoubleInterceptor::class));
$instance = $dependency->inject($container);
assert(is_object($instance));
$isWeave = (new ReflectionClass($instance))->implementsInterface(WeavedInterface::class);
$this->assertTrue($isWeave);
assert(property_exists($instance, 'bindings'));
$this->assertArrayHasKey('returnSame', (array) $instance->bindings);
}
/**
* @dataProvider containerProvider
* @covers \Ray\Di\Dependency::injectWithArgs
*/
public function testInjectWithArgsPostConstruct(Container $container): void
{
$car = $this->dependency->injectWithArgs($container, [new FakeEngine()]);
$this->assertInstanceOf(FakeCar::class, $car);
}
/**
* @dataProvider containerProvider
* @covers \Ray\Di\Dependency::injectWithArgs
*/
public function testInjectWithArgsSingleton(Container $container): void
{
$this->dependency->setScope(Scope::SINGLETON);
$this->dependency->injectWithArgs($container, [new FakeEngine()]);
$car = $this->dependency->injectWithArgs($container, [new FakeEngine()]);
$this->assertInstanceOf(FakeCar::class, $car);
}
}
================================================
FILE: tests/di/Fake/Annotation/FakeInjectOne.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Annotation;
use Attribute;
use Ray\Di\Di\InjectInterface;
use Ray\Di\Di\Qualifier;
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_PARAMETER), Qualifier]
final class FakeInjectOne implements InjectInterface
{
public function isOptional()
{
return false;
}
}
================================================
FILE: tests/di/Fake/Annotation/FakeLeft.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Annotation;
use Attribute;
use Ray\Di\Di\Qualifier;
#[Attribute, Qualifier]
final class FakeLeft
{
}
================================================
FILE: tests/di/Fake/Annotation/FakeNotQualifer.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Annotation;
use Attribute;
use Ray\Di\Di\Qualifier;
#[Attribute]
final class FakeNotQualifer
{
}
================================================
FILE: tests/di/Fake/Annotation/FakeQualifierOnly.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Annotation;
use Attribute;
use Ray\Di\Di\Qualifier;
/**
* Qualifier-only attribute for testing (no InjectInterface)
*/
#[Attribute(Attribute::TARGET_METHOD), Qualifier]
final class FakeQualifierOnly
{
}
================================================
FILE: tests/di/Fake/Annotation/FakeRight.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di\Annotation;
use Attribute;
use Ray\Di\Di\Qualifier;
#[Attribute, Qualifier]
final class FakeRight
{
}
================================================
FILE: tests/di/Fake/FakeAbstractClass.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
abstract class FakeAbstractClass
{
}
================================================
FILE: tests/di/Fake/FakeAbstractDb.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
class FakeAbstractDb
{
public $dbId;
public function __construct($id)
{
$this->dbId = $id;
}
}
================================================
FILE: tests/di/Fake/FakeAnnoClass.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Attribute;
#[Attribute(Attribute::TARGET_CLASS)]
class FakeAnnoClass
{
public static $order = [];
}
================================================
FILE: tests/di/Fake/FakeAnnoInterceptor1.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Aop\MethodInterceptor;
use Ray\Aop\MethodInvocation;
class FakeAnnoInterceptor1 implements MethodInterceptor
{
public function invoke(MethodInvocation $invocation)
{
FakeAnnoClass::$order[] = self::class;
return $invocation->proceed();
}
}
================================================
FILE: tests/di/Fake/FakeAnnoInterceptor2.php
================================================
<?php
declare(strict_types=1);
namespace Ray\Di;
use Ray\Aop\MethodInterceptor;
use Ray\Aop\MethodInvocation;
class FakeAnnoInterceptor2 implements MethodInterceptor
{
public function invoke(MethodInvocation $invocation)
{
FakeAnnoClass::$order[] = self::class;
return $invocation->
gitextract_o85d1j_u/
├── .gitattributes
├── .github/
│ ├── CONTRIBUTING.md
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── feature.md
│ │ └── question.md
│ ├── SECURITY.md
│ └── workflows/
│ ├── coding-standards.yml
│ ├── continuous-integration.yml
│ ├── demo.yml
│ ├── prefer-lowest.yml
│ ├── static-analysis.yml
│ └── update-copyright-years-in-license-file.yml
├── .gitignore
├── .scrutinizer.yml
├── .sonarcloud.properties
├── CLAUDE.md
├── LICENSE
├── README.md
├── codecov.yml
├── composer-require-checker.json
├── composer.json
├── demo/
│ ├── 01a-linked-binding.php
│ ├── 01b-linked-binding-setter-injection.php
│ ├── 02-provider-binding.php
│ ├── 02a-named-by-qualifier.php
│ ├── 02b-named-by-named.php
│ ├── 03-injection-point.php
│ ├── 04-untarget-binding.php
│ ├── 05a-constructor-binding.php
│ ├── 05b-constructor-binding-setter-injection.php
│ ├── 07-assisted-injection.php
│ ├── 10-cache.php
│ ├── 11-script-injector.php
│ ├── 12-dependency-chain-error-message.php
│ ├── chain-error/
│ │ ├── A.php
│ │ ├── B.php
│ │ ├── C.php
│ │ ├── D.php
│ │ └── EInterface.php
│ ├── finder/
│ │ ├── Db.php
│ │ ├── DbFinder.php
│ │ ├── DbInterface.php
│ │ ├── Finder.php
│ │ ├── FinderInterface.php
│ │ ├── FinderModule.php
│ │ ├── MovieFinder.php
│ │ ├── MovieLister.php
│ │ ├── MovieListerInterface.php
│ │ └── Sorter.php
│ ├── run.php
│ └── tmp/
│ └── .gitkeep
├── phpcs.xml
├── phpmd.xml
├── phpstan.neon
├── phpunit.xml.dist
├── psalm.xml
├── rector.php
├── src/
│ └── di/
│ ├── AbstractModule.php
│ ├── AcceptInterface.php
│ ├── AnnotatedClass.php
│ ├── AnnotatedClassMethods.php
│ ├── Annotation/
│ │ └── ScriptDir.php
│ ├── Argument.php
│ ├── Arguments.php
│ ├── AspectBind.php
│ ├── AssistedInjectInterceptor.php
│ ├── AssistedInjectModule.php
│ ├── AssistedModule.php
│ ├── Bind.php
│ ├── BindValidator.php
│ ├── BuiltinModule.php
│ ├── CompileNullObject.php
│ ├── Container.php
│ ├── ContainerFactory.php
│ ├── Dependency.php
│ ├── DependencyFactory.php
│ ├── DependencyInterface.php
│ ├── DependencyProvider.php
│ ├── Di/
│ │ ├── Assisted.php
│ │ ├── Inject.php
│ │ ├── InjectInterface.php
│ │ ├── Named.php
│ │ ├── PostConstruct.php
│ │ ├── Qualifier.php
│ │ └── Set.php
│ ├── Exception/
│ │ ├── DirectoryNotWritable.php
│ │ ├── ExceptionInterface.php
│ │ ├── InvalidContext.php
│ │ ├── InvalidProvider.php
│ │ ├── InvalidToConstructorNameParameter.php
│ │ ├── InvalidType.php
│ │ ├── MethodInvocationNotAvailable.php
│ │ ├── NoHint.php
│ │ ├── NotFound.php
│ │ ├── SetNotFound.php
│ │ ├── Unbound.php
│ │ └── Untargeted.php
│ ├── Exception.php
│ ├── Grapher.php
│ ├── InjectableInterface.php
│ ├── InjectionPoint.php
│ ├── InjectionPointInterface.php
│ ├── InjectionPoints.php
│ ├── Injector.php
│ ├── InjectorInterface.php
│ ├── Instance.php
│ ├── Matcher/
│ │ └── AssistedInjectMatcher.php
│ ├── MethodInvocationProvider.php
│ ├── ModuleString.php
│ ├── MultiBinder.php
│ ├── MultiBinding/
│ │ ├── LazyInstance.php
│ │ ├── LazyInterface.php
│ │ ├── LazyProvider.php
│ │ ├── LazyTo.php
│ │ ├── Map.php
│ │ ├── MapProvider.php
│ │ ├── MultiBindingModule.php
│ │ └── MultiBindings.php
│ ├── Name.php
│ ├── NewInstance.php
│ ├── NullDependency.php
│ ├── NullModule.php
│ ├── NullObjectDependency.php
│ ├── ProviderInterface.php
│ ├── ProviderProvider.php
│ ├── ProviderSetModule.php
│ ├── ProviderSetProvider.php
│ ├── Scope.php
│ ├── SetContextInterface.php
│ ├── SetterMethod.php
│ ├── SetterMethods.php
│ ├── SpyCompiler.php
│ ├── Types.php
│ ├── Untarget.php
│ └── VisitorInterface.php
├── src-deprecated/
│ └── di/
│ ├── BcParameterQualifier.php
│ ├── BcStringParser.php
│ ├── EmptyModule.php
│ ├── NullCache.php
│ └── Provider.php
├── tests/
│ ├── bootstrap.php
│ ├── di/
│ │ ├── AnnotatedClassTest.php
│ │ ├── ArgumentTest.php
│ │ ├── ArgumentsTest.php
│ │ ├── AssistedTest.php
│ │ ├── BcParameterQualifierIntegrationTest.php
│ │ ├── BcParameterQualifierTest.php
│ │ ├── BcStringParserTest.php
│ │ ├── BindTest.php
│ │ ├── ContainerTest.php
│ │ ├── ContextualProviderTest.php
│ │ ├── DependencyTest.php
│ │ ├── Fake/
│ │ │ ├── Annotation/
│ │ │ │ ├── FakeInjectOne.php
│ │ │ │ ├── FakeLeft.php
│ │ │ │ ├── FakeNotQualifer.php
│ │ │ │ ├── FakeQualifierOnly.php
│ │ │ │ └── FakeRight.php
│ │ │ ├── FakeAbstractClass.php
│ │ │ ├── FakeAbstractDb.php
│ │ │ ├── FakeAnnoClass.php
│ │ │ ├── FakeAnnoInterceptor1.php
│ │ │ ├── FakeAnnoInterceptor2.php
│ │ │ ├── FakeAnnoInterceptor3.php
│ │ │ ├── FakeAnnoInterceptor4.php
│ │ │ ├── FakeAnnoInterceptor5.php
│ │ │ ├── FakeAnnoInterceptorInterface.php
│ │ │ ├── FakeAnnoMethod1.php
│ │ │ ├── FakeAnnoMethod2.php
│ │ │ ├── FakeAnnoMethod3.php
│ │ │ ├── FakeAnnoModule.php
│ │ │ ├── FakeAnnoOrderClass.php
│ │ │ ├── FakeAop.php
│ │ │ ├── FakeAopDoublyInstallModule.php
│ │ │ ├── FakeAopGrapher.php
│ │ │ ├── FakeAopGrapherModule.php
│ │ │ ├── FakeAopInstallModule.php
│ │ │ ├── FakeAopInterceptorModule.php
│ │ │ ├── FakeAopInterface.php
│ │ │ ├── FakeAopInterfaceModule.php
│ │ │ ├── FakeAopModule.php
│ │ │ ├── FakeAssistedConsumer.php
│ │ │ ├── FakeAssistedDb.php
│ │ │ ├── FakeAssistedDbModule.php
│ │ │ ├── FakeAssistedDbProvider.php
│ │ │ ├── FakeAssistedInjectConsumer.php
│ │ │ ├── FakeAssistedInjectDb.php
│ │ │ ├── FakeAssistedParamsConsumer.php
│ │ │ ├── FakeBcConstructorQualifierClass.php
│ │ │ ├── FakeBcParameterQualifierClass.php
│ │ │ ├── FakeBcParameterQualifierModule.php
│ │ │ ├── FakeBuiltin.php
│ │ │ ├── FakeCar.php
│ │ │ ├── FakeCarEngine.php
│ │ │ ├── FakeCarEngineModule.php
│ │ │ ├── FakeCarInterface.php
│ │ │ ├── FakeCarModule.php
│ │ │ ├── FakeClassInstanceBindModule.php
│ │ │ ├── FakeClassWithBcParameterQualifier.php
│ │ │ ├── FakeConcreteClass.php
│ │ │ ├── FakeConstant.php
│ │ │ ├── FakeConstantConsumer.php
│ │ │ ├── FakeConstantInterface.php
│ │ │ ├── FakeConstantModule.php
│ │ │ ├── FakeContextualModule.php
│ │ │ ├── FakeContextualProvider.php
│ │ │ ├── FakeContextualRobot.php
│ │ │ ├── FakeDoubleInterceptor.php
│ │ │ ├── FakeDoubleInterceptorInterface.php
│ │ │ ├── FakeEngine.php
│ │ │ ├── FakeEngine2.php
│ │ │ ├── FakeEngine3.php
│ │ │ ├── FakeEngineInterface.php
│ │ │ ├── FakeEngineProvider.php
│ │ │ ├── FakeEngineToProviderModule.php
│ │ │ ├── FakeFormerBindingHasPriorityModule.php
│ │ │ ├── FakeGearStickInject.php
│ │ │ ├── FakeGearStickInterface.php
│ │ │ ├── FakeGearStickProvider.php
│ │ │ ├── FakeHandle.php
│ │ │ ├── FakeHandleBar.php
│ │ │ ├── FakeHandleBarQualifier.php
│ │ │ ├── FakeHandleInterface.php
│ │ │ ├── FakeHandleProvider.php
│ │ │ ├── FakeHardtop.php
│ │ │ ├── FakeHardtopInterface.php
│ │ │ ├── FakeInjectionPoint.php
│ │ │ ├── FakeInstallModule.php
│ │ │ ├── FakeInstanceBindModule.php
│ │ │ ├── FakeInstanceBindModule2.php
│ │ │ ├── FakeInstanceBindModuleOneTo3.php
│ │ │ ├── FakeInternalTypeModule.php
│ │ │ ├── FakeInternalTypes.php
│ │ │ ├── FakeLeatherGearStick.php
│ │ │ ├── FakeLeft.php
│ │ │ ├── FakeLeftLeg.php
│ │ │ ├── FakeLegInterface.php
│ │ │ ├── FakeLogStringModule.php
│ │ │ ├── FakeMirrorInterface.php
│ │ │ ├── FakeMirrorLeft.php
│ │ │ ├── FakeMirrorRight.php
│ │ │ ├── FakeModuleInModule.php
│ │ │ ├── FakeModuleInModuleOverride.php
│ │ │ ├── FakeMultiBindingAnnotation.php
│ │ │ ├── FakeMultiBindingConsumer.php
│ │ │ ├── FakeOnionInterceptor2.php
│ │ │ ├── FakeOnionInterceptor3.php
│ │ │ ├── FakeOnionInterceptor4.php
│ │ │ ├── FakeOpenCarModule.php
│ │ │ ├── FakeOverrideInstallModule.php
│ │ │ ├── FakePdoModule.php
│ │ │ ├── FakePhp8Car.php
│ │ │ ├── FakePhp8CarModule.php
│ │ │ ├── FakePhp8HandleProvider.php
│ │ │ ├── FakePriorityModule.php
│ │ │ ├── FakePropConstruct.php
│ │ │ ├── FakeRenameModule.php
│ │ │ ├── FakeRight.php
│ │ │ ├── FakeRightLeg.php
│ │ │ ├── FakeRobot.php
│ │ │ ├── FakeRobotInterface.php
│ │ │ ├── FakeRobotProvider.php
│ │ │ ├── FakeRobotTeam.php
│ │ │ ├── FakeSet.php
│ │ │ ├── FakeSetNotFoundWithMap.php
│ │ │ ├── FakeSetNotFoundWithProvider.php
│ │ │ ├── FakeToBindInvalidClassModule.php
│ │ │ ├── FakeToBindModule.php
│ │ │ ├── FakeToBindSingletonModule.php
│ │ │ ├── FakeToConstructorRobot.php
│ │ │ ├── FakeToProviderBindModule.php
│ │ │ ├── FakeToProviderSingletonBindModule.php
│ │ │ ├── FakeTyre.php
│ │ │ ├── FakeTyreInterface.php
│ │ │ ├── FakeUnNamedClass.php
│ │ │ ├── FakeUnNamedModule.php
│ │ │ ├── FakeUntarget.php
│ │ │ ├── FakeUntargetChild.php
│ │ │ ├── FakeUntargetModule.php
│ │ │ ├── FakeUntargetToIntanceModule.php
│ │ │ ├── FakeWalkRobot.php
│ │ │ ├── FakeWalkRobotLegProvider.php
│ │ │ ├── FakeWalkRobotModule.php
│ │ │ ├── FakelNoConstructorCallModule.php
│ │ │ └── NullVisitor.php
│ │ ├── GrapherTest.php
│ │ ├── InjectionPointTest.php
│ │ ├── InjectionPointsTest.php
│ │ ├── InjectorTest.php
│ │ ├── ModuleMergerTest.php
│ │ ├── ModuleTest.php
│ │ ├── MultiBinding/
│ │ │ ├── MultiBinderTest.php
│ │ │ └── MultiBindingModuleTest.php
│ │ ├── NameTest.php
│ │ ├── NewInstanceTest.php
│ │ ├── NoHintTest.php
│ │ ├── NullModuleTest.php
│ │ ├── ProviderProviderTest.php
│ │ ├── SetterMethodTest.php
│ │ ├── SetterMethodsTest.php
│ │ ├── SpyCompilerTest.php
│ │ ├── UnboundTest.php
│ │ ├── VisitorTest.php
│ │ └── script/
│ │ ├── aop.php
│ │ ├── bench.php
│ │ └── grapher.php
│ ├── script/
│ │ └── aop.php.cache
│ ├── stub/
│ │ └── BindInterface.phpstub
│ └── type/
│ └── InjectorInterfaceTest.php
├── tests-php8/
│ ├── AssistedInjectTest.php
│ └── DualReaderTest.php
└── vendor-bin/
└── tools/
└── composer.json
SYMBOL INDEX (940 symbols across 273 files)
FILE: demo/01a-linked-binding.php
type FinderInterface (line 10) | interface FinderInterface
class Finder (line 14) | class Finder implements FinderInterface
type MovieListerInterface (line 18) | interface MovieListerInterface
class MovieLister (line 22) | class MovieLister implements MovieListerInterface
method __construct (line 24) | public function __construct(
class FinderModule (line 29) | class FinderModule extends AbstractModule
method configure (line 31) | protected function configure()
FILE: demo/01b-linked-binding-setter-injection.php
type FinderInterface (line 11) | interface FinderInterface
class Finder (line 15) | class Finder implements FinderInterface
type MovieListerInterface (line 19) | interface MovieListerInterface
class MovieLister (line 23) | class MovieLister implements MovieListerInterface
method setFinder (line 27) | #[Inject]
class FinderModule (line 34) | class FinderModule extends AbstractModule
method configure (line 36) | protected function configure()
FILE: demo/02-provider-binding.php
type FinderInterface (line 11) | interface FinderInterface
class Finder (line 15) | class Finder implements FinderInterface
method __construct (line 19) | public function __construct(DateTimeInterface $dateTime)
class FinderProvider (line 25) | class FinderProvider implements ProviderInterface
method get (line 30) | public function get()
type MovieListerInterface (line 36) | interface MovieListerInterface
class MovieLister (line 40) | class MovieLister implements MovieListerInterface
method __construct (line 42) | public function __construct(
class FinderModule (line 48) | class FinderModule extends AbstractModule
method configure (line 50) | protected function configure()
FILE: demo/02a-named-by-qualifier.php
type FinderInterface (line 11) | interface FinderInterface
class LegacyFinder (line 15) | class LegacyFinder implements FinderInterface
type MovieListerInterface (line 19) | interface MovieListerInterface
class MovieLister (line 23) | class MovieLister implements MovieListerInterface
method __construct (line 27) | public function __construct(#[Legacy] FinderInterface $finder)
class Legacy (line 33) | #[Attribute(Attribute::TARGET_PARAMETER), Qualifier]
class FinderModule (line 38) | class FinderModule extends AbstractModule
method configure (line 40) | protected function configure()
FILE: demo/02b-named-by-named.php
type FinderInterface (line 11) | interface FinderInterface
class LegacyFinder (line 15) | class LegacyFinder implements FinderInterface
class ModernFinder (line 19) | class ModernFinder implements FinderInterface
type MovieListerInterface (line 23) | interface MovieListerInterface
class MovieLister (line 27) | class MovieLister implements MovieListerInterface
method __construct (line 29) | public function __construct(
class FinderModule (line 34) | class FinderModule extends AbstractModule
method configure (line 36) | protected function configure()
FILE: demo/03-injection-point.php
type FinderInterface (line 12) | interface FinderInterface
type MovieListerInterface (line 16) | interface MovieListerInterface
class Finder (line 20) | class Finder implements FinderInterface
method __construct (line 24) | public function __construct(string $className)
method find (line 29) | public function find(): string
class MovieLister (line 35) | class MovieLister implements MovieListerInterface
method __construct (line 39) | public function __construct(FinderInterface $finder)
class FinderProvider (line 45) | class FinderProvider implements ProviderInterface
method __construct (line 47) | public function __construct(
method get (line 55) | public function get()
class FinderModule (line 63) | class FinderModule extends AbstractModule
method configure (line 65) | protected function configure()
FILE: demo/04-untarget-binding.php
class Finder (line 11) | class Finder
class FinderModule (line 15) | class FinderModule extends AbstractModule
method configure (line 17) | protected function configure()
FILE: demo/05a-constructor-binding.php
class PdoModuleLegacyNaming (line 12) | class PdoModuleLegacyNaming extends AbstractModule
method configure (line 14) | protected function configure()
class PdoModule (line 22) | class PdoModule extends AbstractModule
method configure (line 24) | protected function configure()
FILE: demo/05b-constructor-binding-setter-injection.php
type FinderInterface (line 17) | interface FinderInterface
type MovieListerInterface (line 20) | interface MovieListerInterface
class Finder (line 24) | class Finder implements FinderInterface
class MovieLister (line 28) | class MovieLister implements MovieListerInterface
method setFinder (line 35) | public function setFinder(FinderInterface $finder)
class ListerModule (line 41) | class ListerModule extends AbstractModule
method configure (line 43) | protected function configure()
FILE: demo/07-assisted-injection.php
method configure (line 14) | protected function configure()
FILE: demo/12-dependency-chain-error-message.php
class DeepLinkedClassBindingModule (line 14) | class DeepLinkedClassBindingModule extends AbstractModule
method configure (line 16) | protected function configure()
FILE: demo/chain-error/A.php
class A (line 5) | class A
method __construct (line 7) | public function __construct(B $b)
FILE: demo/chain-error/B.php
class B (line 5) | class B
method __construct (line 7) | public function __construct(C $c)
FILE: demo/chain-error/C.php
class C (line 5) | class C
method __construct (line 7) | public function __construct(D $d)
FILE: demo/chain-error/D.php
class D (line 5) | class D
method __construct (line 7) | public function __construct(EInterface $e)
FILE: demo/chain-error/EInterface.php
type EInterface (line 5) | interface EInterface
FILE: demo/finder/Db.php
class Db (line 7) | class Db implements DbInterface
method __construct (line 9) | public function __construct($dsn, $username, $password)
method init (line 13) | #[PostConstruct]
FILE: demo/finder/DbFinder.php
class DbFinder (line 7) | class DbFinder implements FinderInterface
method __construct (line 9) | public function __construct(DbInterface $db)
method setDb (line 13) | #[Inject]
method setSorter (line 18) | #[Inject]
FILE: demo/finder/DbInterface.php
type DbInterface (line 5) | interface DbInterface
FILE: demo/finder/Finder.php
class Finder (line 5) | class Finder implements FinderInterface
FILE: demo/finder/FinderInterface.php
type FinderInterface (line 5) | interface FinderInterface
FILE: demo/finder/FinderModule.php
class FinderModule (line 8) | class FinderModule extends AbstractModule
method configure (line 10) | protected function configure()
FILE: demo/finder/MovieFinder.php
class MovieFinder (line 8) | class MovieFinder
method find (line 10) | public function find($name, #[Inject] ?FinderInterface $finder = null)
FILE: demo/finder/MovieLister.php
class MovieLister (line 7) | class MovieLister implements MovieListerInterface
method __construct (line 9) | public function __construct(FinderInterface $finder)
method setFinder01 (line 13) | #[Inject]
FILE: demo/finder/MovieListerInterface.php
type MovieListerInterface (line 5) | interface MovieListerInterface
FILE: demo/finder/Sorter.php
class Sorter (line 5) | class Sorter
FILE: src-deprecated/di/BcParameterQualifier.php
class BcParameterQualifier (line 42) | final class BcParameterQualifier
method getNames (line 57) | public static function getNames(ReflectionMethod $method): array
method getQualifier (line 87) | private static function getQualifier(ReflectionMethod $method): string
method hasParameterQualifier (line 136) | private static function hasParameterQualifier(array $attributes): bool
FILE: src-deprecated/di/BcStringParser.php
class BcStringParser (line 21) | final class BcStringParser
method parse (line 30) | public static function parse(string $name): array
FILE: src-deprecated/di/EmptyModule.php
class EmptyModule (line 10) | class EmptyModule extends AbstractModule
method configure (line 15) | protected function configure() : void
FILE: src-deprecated/di/NullCache.php
class NullCache (line 13) | final class NullCache extends CacheProvider
method doFetch (line 18) | protected function doFetch($id)
method doContains (line 26) | protected function doContains($id)
method doSave (line 34) | protected function doSave($id, $data, $lifeTime = 0)
method doDelete (line 42) | protected function doDelete($id)
method doFlush (line 50) | protected function doFlush()
method doGetStats (line 58) | protected function doGetStats()
FILE: src-deprecated/di/Provider.php
type Provider (line 10) | interface Provider extends ProviderInterface
FILE: src/di/AbstractModule.php
class AbstractModule (line 22) | abstract class AbstractModule implements Stringable
method __construct (line 31) | public function __construct(
method __toString (line 41) | public function __toString(): string
method install (line 49) | public function install(self $module): void
method override (line 57) | public function override(self $module): void
method getContainer (line 66) | public function getContainer(): Container
method bindInterceptor (line 82) | public function bindInterceptor(AbstractMatcher $classMatcher, Abstrac...
method bindPriorityInterceptor (line 103) | public function bindPriorityInterceptor(AbstractMatcher $classMatcher,...
method rename (line 120) | public function rename(string $interface, string $newName, string $sou...
method configure (line 135) | abstract protected function configure();
method bind (line 142) | protected function bind(string $interface = ''): Bind
method activate (line 150) | private function activate(): void
FILE: src/di/AcceptInterface.php
type AcceptInterface (line 10) | interface AcceptInterface
method accept (line 19) | public function accept(VisitorInterface $visitor);
FILE: src/di/AnnotatedClass.php
class AnnotatedClass (line 11) | final class AnnotatedClass
method __construct (line 15) | public function __construct()
method getNewInstance (line 25) | public function getNewInstance(ReflectionClass $class): NewInstance
method getPostConstruct (line 47) | public function getPostConstruct(ReflectionClass $class): ?ReflectionM...
FILE: src/di/AnnotatedClassMethods.php
class AnnotatedClassMethods (line 12) | final class AnnotatedClassMethods
method getConstructorName (line 17) | public function getConstructorName(ReflectionClass $class): Name
method getSetterMethod (line 33) | public function getSetterMethod(ReflectionMethod $method): ?SetterMethod
method getName (line 49) | private function getName(ReflectionMethod $method): Name
FILE: src/di/Annotation/ScriptDir.php
class ScriptDir (line 15) | #[Attribute, Qualifier]
FILE: src/di/Argument.php
class Argument (line 20) | final class Argument implements AcceptInterface, Stringable
method __construct (line 33) | public function __construct(ReflectionParameter $parameter, string $name)
method __toString (line 60) | public function __toString(): string
method get (line 68) | public function get(): ReflectionParameter
method isDefaultAvailable (line 73) | public function isDefaultAvailable(): bool
method getDefaultValue (line 81) | public function getDefaultValue()
method getMeta (line 86) | public function getMeta(): string
method __serialize (line 94) | public function __serialize(): array
method __unserialize (line 116) | public function __unserialize(array $unserialized): void
method accept (line 129) | public function accept(VisitorInterface $visitor): void
method setDefaultValue (line 139) | private function setDefaultValue(ReflectionParameter $parameter): void
method getType (line 157) | private function getType(ReflectionParameter $parameter): string
FILE: src/di/Arguments.php
class Arguments (line 17) | final class Arguments implements AcceptInterface
method __construct (line 22) | public function __construct(ReflectionMethod $method, Name $name)
method inject (line 37) | public function inject(Container $container): array
method accept (line 48) | public function accept(VisitorInterface $visitor): void
method getParameter (line 58) | private function getParameter(Container $container, Argument $argument)
method bindInjectionPoint (line 76) | private function bindInjectionPoint(Container $container, Argument $ar...
method getNoHintMsg (line 86) | private function getNoHintMsg(Argument $argument): string
FILE: src/di/AspectBind.php
class AspectBind (line 15) | final class AspectBind implements AcceptInterface
method __construct (line 17) | public function __construct(private AopBind $bind)
method inject (line 26) | public function inject(Container $container): array
method accept (line 46) | public function accept(VisitorInterface $visitor): void
FILE: src/di/AssistedInjectInterceptor.php
class AssistedInjectInterceptor (line 32) | final class AssistedInjectInterceptor implements MethodInterceptor
method __construct (line 34) | public function __construct(private InjectorInterface $injector, priva...
method invoke (line 41) | public function invoke(MethodInvocation $invocation)
method getNamedArguments (line 68) | private function getNamedArguments(MethodInvocation $invocation): array
method getDependency (line 87) | private function getDependency(ReflectionParameter $param)
method getName (line 99) | private function getName(ReflectionParameter $param): ?string
method getCustomInject (line 120) | private function getCustomInject(ReflectionParameter $param): ?string
FILE: src/di/AssistedInjectModule.php
class AssistedInjectModule (line 12) | final class AssistedInjectModule extends AbstractModule
method configure (line 14) | protected function configure(): void
FILE: src/di/AssistedModule.php
class AssistedModule (line 16) | final class AssistedModule extends AbstractModule
method configure (line 18) | protected function configure(): void
FILE: src/di/Bind.php
class Bind (line 22) | final class Bind implements Stringable
method __construct (line 36) | public function __construct(
method __destruct (line 54) | public function __destruct()
method __toString (line 65) | public function __toString(): string
method annotatedWith (line 75) | public function annotatedWith(string $name): self
method to (line 87) | public function to(string $class): self
method toConstructor (line 107) | public function toConstructor(string $class, string|array $name, ?Inje...
method toProvider (line 124) | public function toProvider(string $provider, string $context = ''): self
method toInstance (line 139) | public function toInstance($instance): self
method toNull (line 151) | public function toNull(): self
method in (line 164) | public function in(string $scope): self
method getBound (line 177) | public function getBound(): DependencyInterface
method setBound (line 182) | public function setBound(DependencyInterface $bound): void
method isRegistered (line 187) | private function isRegistered(string $interface): bool
FILE: src/di/BindValidator.php
class BindValidator (line 18) | final class BindValidator
method constructor (line 20) | public function constructor(string $interface): void
method to (line 36) | public function to(string $interface, string $class): ReflectionClass
method toProvider (line 59) | public function toProvider(string $provider): ReflectionClass
method isNullInterceptorBinding (line 74) | private function isNullInterceptorBinding(string $class, string $inter...
FILE: src/di/BuiltinModule.php
class BuiltinModule (line 9) | final class BuiltinModule
method __invoke (line 11) | public function __invoke(AbstractModule $module): AbstractModule
FILE: src/di/CompileNullObject.php
class CompileNullObject (line 10) | final class CompileNullObject
method __invoke (line 12) | public function __invoke(Container $container, string $scriptDir): void
FILE: src/di/Container.php
class Container (line 30) | final class Container implements InjectorInterface
method __construct (line 41) | public function __construct()
method __sleep (line 49) | public function __sleep()
method add (line 57) | public function add(Bind $bind): void
method addPointcut (line 66) | public function addPointcut(Pointcut $pointcut): void
method getInstance (line 81) | public function getInstance($interface, $name = Name::ANY)
method getInstanceWithArgs (line 96) | public function getInstanceWithArgs(string $interface, array $params)
method getDependency (line 120) | public function getDependency(string $index)
method move (line 132) | public function move(string $sourceInterface, string $sourceName, stri...
method unbound (line 149) | public function unbound(string $index): Untargeted|Unbound
method getContainer (line 169) | public function getContainer(): array
method getPointcuts (line 180) | public function getPointcuts(): array
method merge (line 188) | public function merge(self $container): void
method weaveAspects (line 198) | public function weaveAspects(CompilerInterface $compiler): void
method weaveAspect (line 214) | public function weaveAspect(Compiler $compiler, Dependency $dependency...
method map (line 224) | public function map(callable $f): void
method sort (line 231) | public function sort(): void
FILE: src/di/ContainerFactory.php
class ContainerFactory (line 15) | final class ContainerFactory
method __invoke (line 21) | public function __invoke($module, string $classDir): Container
method getModule (line 39) | private function getModule($module): AbstractModule
FILE: src/di/Dependency.php
class Dependency (line 22) | final class Dependency implements DependencyInterface, AcceptInterface
method __construct (line 34) | public function __construct(NewInstance $newInstance, ?ReflectionMetho...
method __sleep (line 43) | public function __sleep()
method __toString (line 48) | public function __toString(): string
method register (line 59) | public function register(array &$container, Bind $bind): void
method inject (line 67) | public function inject(Container $container)
method injectWithArgs (line 91) | public function injectWithArgs(Container $container, array $params)
method setScope (line 113) | public function setScope($scope): void
method weaveAspects (line 123) | public function weaveAspects(CompilerInterface $compiler, array $point...
method accept (line 148) | public function accept(VisitorInterface $visitor)
method isSingleton (line 157) | public function isSingleton(): bool
FILE: src/di/DependencyFactory.php
class DependencyFactory (line 13) | final class DependencyFactory
method newAnnotatedDependency (line 20) | public function newAnnotatedDependency(ReflectionClass $class): Depend...
method newProvider (line 34) | public function newProvider(ReflectionClass $provider, string $context...
method newToConstructor (line 47) | public function newToConstructor(
FILE: src/di/DependencyInterface.php
type DependencyInterface (line 12) | interface DependencyInterface
method __toString (line 17) | public function __toString();
method inject (line 24) | public function inject(Container $container);
method register (line 35) | public function register(array &$container, Bind $bind);
method setScope (line 44) | public function setScope($scope);
FILE: src/di/DependencyProvider.php
class DependencyProvider (line 10) | final class DependencyProvider implements DependencyInterface, AcceptInt...
method __construct (line 17) | public function __construct(
method __sleep (line 29) | public function __sleep()
method __toString (line 34) | public function __toString(): string
method register (line 45) | public function register(array &$container, Bind $bind): void
method inject (line 53) | public function inject(Container $container)
method setScope (line 73) | public function setScope($scope): void
method setContext (line 80) | public function setContext(SetContextInterface $provider): void
method isSingleton (line 85) | public function isSingleton(): bool
method accept (line 91) | public function accept(VisitorInterface $visitor)
FILE: src/di/Di/Assisted.php
class Assisted (line 15) | #[Attribute(Attribute::TARGET_PARAMETER)]
FILE: src/di/Di/Inject.php
class Inject (line 14) | #[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_PARAMETER)]
method __construct (line 20) | public function __construct(
method isOptional (line 31) | public function isOptional(): bool
FILE: src/di/Di/InjectInterface.php
type InjectInterface (line 7) | interface InjectInterface
method isOptional (line 14) | public function isOptional();
FILE: src/di/Di/Named.php
class Named (line 14) | #[Attribute(Attribute::TARGET_PARAMETER | Attribute::TARGET_METHOD | Att...
method __construct (line 17) | public function __construct(public string $value)
FILE: src/di/Di/PostConstruct.php
class PostConstruct (line 21) | #[Attribute(Attribute::TARGET_METHOD)]
FILE: src/di/Di/Qualifier.php
class Qualifier (line 12) | #[Attribute(Attribute::TARGET_CLASS)]
FILE: src/di/Di/Set.php
class Set (line 13) | #[Attribute(Attribute::TARGET_PARAMETER | Attribute::TARGET_PROPERTY)]
method __construct (line 19) | public function __construct(public string $interface, public string $n...
FILE: src/di/Exception.php
class Exception (line 7) | final class Exception extends \Exception
FILE: src/di/Exception/DirectoryNotWritable.php
class DirectoryNotWritable (line 9) | final class DirectoryNotWritable extends RuntimeException implements Exc...
FILE: src/di/Exception/ExceptionInterface.php
type ExceptionInterface (line 7) | interface ExceptionInterface
FILE: src/di/Exception/InvalidContext.php
class InvalidContext (line 9) | final class InvalidContext extends InvalidArgumentException implements E...
FILE: src/di/Exception/InvalidProvider.php
class InvalidProvider (line 9) | final class InvalidProvider extends InvalidArgumentException implements ...
FILE: src/di/Exception/InvalidToConstructorNameParameter.php
class InvalidToConstructorNameParameter (line 12) | final class InvalidToConstructorNameParameter extends InvalidArgumentExc...
FILE: src/di/Exception/InvalidType.php
class InvalidType (line 9) | final class InvalidType extends InvalidArgumentException implements Exce...
FILE: src/di/Exception/MethodInvocationNotAvailable.php
class MethodInvocationNotAvailable (line 7) | final class MethodInvocationNotAvailable extends Unbound
FILE: src/di/Exception/NoHint.php
class NoHint (line 15) | final class NoHint extends Unbound
FILE: src/di/Exception/NotFound.php
class NotFound (line 9) | final class NotFound extends LogicException implements ExceptionInterface
FILE: src/di/Exception/SetNotFound.php
class SetNotFound (line 9) | final class SetNotFound extends LogicException implements ExceptionInter...
FILE: src/di/Exception/Unbound.php
class Unbound (line 25) | class Unbound extends LogicException implements ExceptionInterface
method __toString (line 27) | public function __toString(): string
method buildMessage (line 45) | private function buildMessage(self $e, array $msg): string
method getMainMessage (line 63) | private function getMainMessage(self $e): string
FILE: src/di/Exception/Untargeted.php
class Untargeted (line 7) | final class Untargeted extends Unbound
FILE: src/di/Grapher.php
class Grapher (line 18) | final class Grapher
method __construct (line 26) | public function __construct(AbstractModule $module, private string $cl...
method __wakeup (line 40) | public function __wakeup()
method newInstanceArgs (line 60) | public function newInstanceArgs(string $class, array $params)
FILE: src/di/InjectableInterface.php
type InjectableInterface (line 7) | interface InjectableInterface
FILE: src/di/InjectionPoint.php
class InjectionPoint (line 15) | final class InjectionPoint implements InjectionPointInterface
method __construct (line 25) | public function __construct(private ReflectionParameter $parameter)
method getParameter (line 36) | public function getParameter(): ReflectionParameter
method getMethod (line 44) | public function getMethod(): ReflectionMethod
method getClass (line 58) | public function getClass(): ReflectionClass
method getQualifiers (line 70) | public function getQualifiers(): array
method __serialize (line 87) | public function __serialize(): array
method __unserialize (line 95) | public function __unserialize(array $array): void
FILE: src/di/InjectionPointInterface.php
type InjectionPointInterface (line 14) | interface InjectionPointInterface
method getParameter (line 19) | public function getParameter(): ReflectionParameter;
method getMethod (line 24) | public function getMethod(): ReflectionMethod;
method getClass (line 32) | public function getClass(): ReflectionClass;
method getQualifiers (line 39) | public function getQualifiers(): array;
FILE: src/di/InjectionPoints.php
class InjectionPoints (line 14) | final class InjectionPoints
method __invoke (line 28) | public function __invoke(string $class): SetterMethods
method addMethod (line 38) | public function addMethod(string $method, string $name = Name::ANY): self
method addOptionalMethod (line 45) | public function addOptionalMethod(string $method, string $name = Name:...
method getSetterMethod (line 58) | private function getSetterMethod(string $class, array $point): SetterM...
FILE: src/di/Injector.php
class Injector (line 25) | final class Injector implements InjectorInterface
method __construct (line 35) | public function __construct($module = null, string $tmpDir = '')
method __wakeup (line 53) | public function __wakeup()
method getInstance (line 68) | public function getInstance($interface, $name = Name::ANY)
method bind (line 87) | private function bind(string $class): void
FILE: src/di/InjectorInterface.php
type InjectorInterface (line 14) | interface InjectorInterface
method getInstance (line 26) | public function getInstance($interface, $name = Name::ANY);
FILE: src/di/Instance.php
class Instance (line 12) | final class Instance implements DependencyInterface, AcceptInterface
method __construct (line 17) | public function __construct(public $value)
method __toString (line 21) | public function __toString(): string
method register (line 41) | public function register(array &$container, Bind $bind): void
method inject (line 50) | public function inject(Container $container)
method setScope (line 60) | public function setScope($scope): void
method accept (line 65) | public function accept(VisitorInterface $visitor)
FILE: src/di/Matcher/AssistedInjectMatcher.php
class AssistedInjectMatcher (line 15) | final class AssistedInjectMatcher extends AbstractMatcher
method matchesClass (line 22) | public function matchesClass(ReflectionClass $class, array $arguments)...
method matchesMethod (line 30) | public function matchesMethod(ReflectionMethod $method, array $argumen...
FILE: src/di/MethodInvocationProvider.php
class MethodInvocationProvider (line 13) | final class MethodInvocationProvider implements ProviderInterface
method set (line 21) | public function set(MethodInvocation $invocation): void
method get (line 29) | public function get(): MethodInvocation
FILE: src/di/ModuleString.php
class ModuleString (line 19) | final class ModuleString
method __invoke (line 24) | public function __invoke(Container $container, array $pointcuts): string
FILE: src/di/MultiBinder.php
class MultiBinder (line 17) | final class MultiBinder
method __construct (line 25) | private function __construct(AbstractModule $module, private readonly ...
method newInstance (line 34) | public static function newInstance(AbstractModule $module, string $int...
method addBinding (line 39) | public function addBinding(?string $key = null): self
method setBinding (line 46) | public function setBinding(?string $key = null): self
method to (line 57) | public function to(string $class): void
method toProvider (line 67) | public function toProvider(string $provider): void
method toInstance (line 75) | public function toInstance($instance): void
method bind (line 80) | private function bind(LazyInterface $lazy, ?string $key): void
FILE: src/di/MultiBinding/LazyInstance.php
class LazyInstance (line 13) | final class LazyInstance implements LazyInterface
method __construct (line 18) | public function __construct(private $instance)
method __invoke (line 25) | public function __invoke(InjectorInterface $injector)
FILE: src/di/MultiBinding/LazyInterface.php
type LazyInterface (line 9) | interface LazyInterface
method __invoke (line 14) | public function __invoke(InjectorInterface $injector);
FILE: src/di/MultiBinding/LazyProvider.php
class LazyProvider (line 13) | final class LazyProvider implements LazyInterface
method __construct (line 18) | public function __construct(private string $class)
method __invoke (line 25) | public function __invoke(InjectorInterface $injector)
FILE: src/di/MultiBinding/LazyTo.php
class LazyTo (line 12) | final class LazyTo implements LazyInterface
method __construct (line 17) | public function __construct(private string $class)
method __invoke (line 24) | public function __invoke(InjectorInterface $injector)
FILE: src/di/MultiBinding/Map.php
class Map (line 24) | final class Map implements IteratorAggregate, ArrayAccess, Countable
method __construct (line 29) | public function __construct(private array $lazies, private readonly In...
method offsetExists (line 38) | #[ReturnTypeWillChange]
method offsetGet (line 51) | #[ReturnTypeWillChange]
method offsetSet (line 68) | #[ReturnTypeWillChange]
method offsetUnset (line 83) | #[ReturnTypeWillChange]
method getIterator (line 92) | public function getIterator(): Iterator
method count (line 102) | public function count(): int
FILE: src/di/MultiBinding/MapProvider.php
class MapProvider (line 16) | final class MapProvider implements ProviderInterface
method __construct (line 18) | public function __construct(private readonly InjectionPointInterface $...
method get (line 25) | public function get(): Map
FILE: src/di/MultiBinding/MultiBindingModule.php
class MultiBindingModule (line 13) | final class MultiBindingModule extends AbstractModule
method configure (line 15) | protected function configure(): void
FILE: src/di/MultiBinding/MultiBindings.php
class MultiBindings (line 16) | final class MultiBindings extends ArrayObject
method merge (line 18) | public function merge(self $multiBindings): void
FILE: src/di/Name.php
class Name (line 22) | final class Name
method __construct (line 43) | public function __construct(string|array $name)
method withAttributes (line 59) | public static function withAttributes(ReflectionMethod $method): ?self
method getName (line 93) | private static function getName(array $attributes): string
method __invoke (line 109) | public function __invoke(ReflectionParameter $parameter): string
method setName (line 122) | private function setName(string $name): void
FILE: src/di/NewInstance.php
class NewInstance (line 18) | final class NewInstance implements Stringable
method __construct (line 31) | public function __construct(
method __invoke (line 49) | public function __invoke(Container $container): object
method __toString (line 61) | public function __toString(): string
method newInstanceArgs (line 71) | public function newInstanceArgs(Container $container, array $params): ...
method weaveAspects (line 81) | public function weaveAspects(string $class, AopBind $bind): void
method accept (line 87) | public function accept(VisitorInterface $visitor): void
method postNewInstance (line 97) | private function postNewInstance(Container $container, object $instanc...
method enableAop (line 107) | public function enableAop(object $instance, Container $container): void
FILE: src/di/NullDependency.php
class NullDependency (line 10) | final class NullDependency implements DependencyInterface
method __toString (line 15) | public function __toString(): string
method inject (line 23) | public function inject(Container $container): void
method register (line 30) | public function register(array &$container, Bind $bind): void
method setScope (line 38) | public function setScope($scope): void
FILE: src/di/NullModule.php
class NullModule (line 7) | final class NullModule extends AbstractModule
method configure (line 9) | protected function configure(): void
FILE: src/di/NullObjectDependency.php
class NullObjectDependency (line 16) | final class NullObjectDependency implements DependencyInterface
method __construct (line 21) | public function __construct(private string $interface)
method __toString (line 28) | public function __toString(): string
method inject (line 36) | public function inject(Container $container): null
method register (line 44) | public function register(array &$container, Bind $bind): void
method setScope (line 52) | public function setScope($scope): void
method toNull (line 56) | public function toNull(string $scriptDir): Dependency
FILE: src/di/ProviderInterface.php
type ProviderInterface (line 10) | interface ProviderInterface
method get (line 15) | public function get();
FILE: src/di/ProviderProvider.php
class ProviderProvider (line 13) | final class ProviderProvider implements ProviderInterface
method __construct (line 16) | public function __construct(private InjectorInterface $injector, priva...
method get (line 21) | public function get()
FILE: src/di/ProviderSetModule.php
class ProviderSetModule (line 7) | final class ProviderSetModule extends AbstractModule
method configure (line 9) | protected function configure(): void
FILE: src/di/ProviderSetProvider.php
class ProviderSetProvider (line 14) | final class ProviderSetProvider implements ProviderInterface
method __construct (line 16) | public function __construct(private InjectionPointInterface $ip, priva...
method get (line 21) | public function get(): ProviderProvider
FILE: src/di/Scope.php
class Scope (line 7) | final class Scope
FILE: src/di/SetContextInterface.php
type SetContextInterface (line 7) | interface SetContextInterface
method setContext (line 16) | public function setContext($context);
FILE: src/di/SetterMethod.php
class SetterMethod (line 15) | final class SetterMethod implements AcceptInterface
method __construct (line 25) | public function __construct(ReflectionMethod $method, Name $name)
method __invoke (line 37) | public function __invoke($instance, Container $container): void
method setOptional (line 57) | public function setOptional(): void
method accept (line 63) | public function accept(VisitorInterface $visitor): void
FILE: src/di/SetterMethods.php
class SetterMethods (line 12) | final class SetterMethods implements AcceptInterface
method __construct (line 17) | public function __construct(private array $setterMethods)
method __invoke (line 24) | public function __invoke(object $instance, Container $container): void
method add (line 31) | public function add(?SetterMethod $setterMethod = null): void
method accept (line 41) | public function accept(VisitorInterface $visitor): void
FILE: src/di/SpyCompiler.php
class SpyCompiler (line 19) | final class SpyCompiler implements CompilerInterface
method newInstance (line 29) | public function newInstance(string $class, array $args, BindInterface ...
method compile (line 45) | public function compile(string $class, BindInterface $bind): string
method hasNoBinding (line 57) | private function hasNoBinding(string $class, BindInterface $bind): bool
method hasBoundMethod (line 67) | private function hasBoundMethod(string $class, BindInterface $bind): bool
method getInterceptors (line 80) | private function getInterceptors(BindInterface $bind): string
FILE: src/di/Types.php
class Types (line 70) | final class Types
FILE: src/di/Untarget.php
class Untarget (line 9) | final class Untarget
method __construct (line 21) | public function __construct(string $class)
method __invoke (line 29) | public function __invoke(Container $container, Bind $bind): void
method setScope (line 38) | public function setScope(string $scope): void
FILE: src/di/VisitorInterface.php
type VisitorInterface (line 16) | interface VisitorInterface
method visitDependency (line 23) | public function visitDependency(NewInstance $newInstance, ?string $pos...
method visitProvider (line 30) | public function visitProvider(Dependency $dependency, string $context,...
method visitInstance (line 39) | public function visitInstance($value);
method visitAspectBind (line 46) | public function visitAspectBind(AopBind $aopBind);
method visitNewInstance (line 53) | public function visitNewInstance(
method visitSetterMethods (line 67) | public function visitSetterMethods(array $setterMethods);
method visitSetterMethod (line 74) | public function visitSetterMethod(string $method, Arguments $arguments);
method visitArguments (line 83) | public function visitArguments(array $arguments);
method visitArgument (line 92) | public function visitArgument(
FILE: tests-php8/AssistedInjectTest.php
class AssistedInjectTest (line 10) | class AssistedInjectTest extends TestCase
method setUp (line 15) | protected function setUp(): void
method testAssisted (line 20) | public function testAssisted(): void
method testAssistedWithName (line 29) | public function testAssistedWithName(): void
method testAssistedAnyWithName (line 39) | public function testAssistedAnyWithName(): void
method testAssistedMethodInvocation (line 50) | public function testAssistedMethodInvocation(): void
method testAssistedCustomeInject (line 60) | public function testAssistedCustomeInject(): void
method testConstructorPropertyPromotion (line 73) | public function testConstructorPropertyPromotion(): void
FILE: tests-php8/DualReaderTest.php
class DualReaderTest (line 11) | class DualReaderTest extends TestCase
method testPhp8Attribute (line 13) | public function testPhp8Attribute(): FakePhp8Car
method testNamedParameterInMethod (line 25) | public function testNamedParameterInMethod(FakePhp8Car $car): void
method testNamedParameterInConstructor (line 36) | public function testNamedParameterInConstructor(FakePhp8Car $car): void
method testPostConstruct (line 44) | public function testPostConstruct(FakePhp8Car $car): void
method testCunstomInjectAnnotation (line 52) | public function testCunstomInjectAnnotation(FakePhp8Car $car): void
method testProviderAttribute (line 60) | public function testProviderAttribute(FakePhp8Car $car): void
method testCumstomInject (line 69) | public function testCumstomInject(FakePhp8Car $car): void
FILE: tests/di/AnnotatedClassTest.php
class AnnotatedClassTest (line 11) | class AnnotatedClassTest extends TestCase
method setUp (line 16) | protected function setUp(): void
method testInvoke (line 22) | public function testInvoke(): void
method testAnnotatedByAnnotation (line 50) | public function testAnnotatedByAnnotation(string $class): void
method classProvider (line 68) | public function classProvider(): array
FILE: tests/di/ArgumentTest.php
class ArgumentTest (line 15) | class ArgumentTest extends TestCase
method setUp (line 20) | protected function setUp(): void
method testToString (line 25) | public function testToString(): void
method testToStringScalar (line 30) | public function testToStringScalar(): void
method testSerializable (line 36) | public function testSerializable(): void
FILE: tests/di/ArgumentsTest.php
class ArgumentsTest (line 13) | class ArgumentsTest extends TestCase
method setUp (line 18) | protected function setUp(): void
method testInject (line 23) | public function testInject(): void
method testParameterDefaultValue (line 33) | public function testParameterDefaultValue(): void
FILE: tests/di/AssistedTest.php
class AssistedTest (line 10) | class AssistedTest extends TestCase
method setUp (line 15) | protected function setUp(): void
method testAssisted (line 20) | public function testAssisted(): void
method testAssistedWithName (line 28) | public function testAssistedWithName(): void
method testAssistedAnyWithName (line 37) | public function testAssistedAnyWithName(): void
method testAssistedMethodInvocation (line 47) | public function testAssistedMethodInvocation(): void
method testAssistedMethodInvocationNotAvailable (line 56) | public function testAssistedMethodInvocationNotAvailable(): void
method testAssistedCustomInject (line 63) | public function testAssistedCustomInject(): void
FILE: tests/di/BcParameterQualifierIntegrationTest.php
class BcParameterQualifierIntegrationTest (line 9) | class BcParameterQualifierIntegrationTest extends TestCase
method testBcParameterQualifierWorks (line 11) | public function testBcParameterQualifierWorks(): void
FILE: tests/di/BcParameterQualifierTest.php
class BcParameterQualifierTest (line 12) | class BcParameterQualifierTest extends TestCase
method testGetNamesFromMethodLevelAttribute (line 14) | public function testGetNamesFromMethodLevelAttribute(): void
method testNoNamesForMultipleParameters (line 23) | public function testNoNamesForMultipleParameters(): void
method testNoNamesWhenParameterHasQualifier (line 32) | public function testNoNamesWhenParameterHasQualifier(): void
method testNoNamesForNonQualifierAttribute (line 41) | public function testNoNamesForNonQualifierAttribute(): void
method testNoNamesForMethodWithoutInjectInterface (line 50) | public function testNoNamesForMethodWithoutInjectInterface(): void
method testNamesForTargetMethodOnly (line 59) | public function testNamesForTargetMethodOnly(): void
method testConstructorWithQualifierOnly (line 70) | public function testConstructorWithQualifierOnly(): void
FILE: tests/di/BcStringParserTest.php
class BcStringParserTest (line 9) | class BcStringParserTest extends TestCase
method testParseStringFormat (line 11) | public function testParseStringFormat(): void
method testParseStringFormatWithSpaces (line 18) | public function testParseStringFormatWithSpaces(): void
method testParseStringFormatWithDollarPrefix (line 25) | public function testParseStringFormatWithDollarPrefix(): void
FILE: tests/di/BindTest.php
class BindTest (line 16) | class BindTest extends TestCase
method setUp (line 21) | protected function setUp(): void
method testGetBound (line 27) | public function testGetBound(): void
method testToString (line 34) | public function testToString(): void
method testInvalidToTest (line 39) | public function testInvalidToTest(): void
method testInvalidToProviderTest (line 45) | public function testInvalidToProviderTest(): void
method testInValidInterfaceBinding (line 51) | public function testInValidInterfaceBinding(): void
method testUntargetedBind (line 57) | public function testUntargetedBind(): void
method testUntargetedBindSingleton (line 66) | public function testUntargetedBindSingleton(): void
method nameProvider (line 79) | public function nameProvider(): array
method testToConstructor (line 91) | public function testToConstructor($name): void
method testToConstructorWithMethodInjection (line 103) | public function testToConstructorWithMethodInjection(): void
method testToValidation (line 121) | public function testToValidation(): void
method testToProvider (line 127) | public function testToProvider(): void
method testBindProviderAsProvider (line 133) | public function testBindProviderAsProvider(): void
method testBindProviderAsProviderInSingleton (line 141) | public function testBindProviderAsProviderInSingleton(): void
method testProviderContext (line 150) | public function testProviderContext(): void
FILE: tests/di/ContainerTest.php
class ContainerTest (line 19) | class ContainerTest extends TestCase
method setUp (line 27) | protected function setUp(): void
method testGetDependency (line 35) | public function testGetDependency(): void
method testClassGetDependency (line 43) | public function testClassGetDependency(): void
method testProviderGetDependency (line 52) | public function testProviderGetDependency(): void
method testGetInstance (line 60) | public function testGetInstance(): void
method testClassGetInstance (line 67) | public function testClassGetInstance(): void
method testProviderGetInstance (line 75) | public function testProviderGetInstance(): void
method testGetContainer (line 82) | public function testGetContainer(): void
method testClassGetContainer (line 89) | public function testClassGetContainer(): void
method testMerge (line 97) | public function testMerge(): void
method testMergePointcuts (line 108) | public function testMergePointcuts(): void
method testMove (line 124) | public function testMove(): void
method testMoveUnbound (line 133) | public function testMoveUnbound(): void
method testAbstractClassUnbound (line 139) | public function testAbstractClassUnbound(): void
method testAnnotateConstant (line 148) | public function testAnnotateConstant(): void
method testBadMethodCall (line 162) | public function testBadMethodCall(): void
method testUnbound (line 174) | public function testUnbound(): void
method testWeaveAspectsWithEmptyPointcuts (line 180) | public function testWeaveAspectsWithEmptyPointcuts(): void
FILE: tests/di/ContextualProviderTest.php
class ContextualProviderTest (line 9) | class ContextualProviderTest extends TestCase
method testContextualProviderInjection (line 11) | public function testContextualProviderInjection(): void
FILE: tests/di/DependencyTest.php
class DependencyTest (line 20) | class DependencyTest extends TestCase
method setUp (line 25) | protected function setUp(): void
method containerProvider (line 42) | public function containerProvider(): array
method testInject (line 55) | public function testInject(Container $container): void
method testSetterInjection (line 65) | public function testSetterInjection(Container $container): void
method testPostConstruct (line 76) | public function testPostConstruct(Container $container): void
method testPrototype (line 86) | public function testPrototype(Container $container): void
method testSingleton (line 98) | public function testSingleton(Container $container): void
method testInjectInterceptor (line 107) | public function testInjectInterceptor(): void
method testInjectWithArgsPostConstruct (line 128) | public function testInjectWithArgsPostConstruct(Container $container):...
method testInjectWithArgsSingleton (line 138) | public function testInjectWithArgsSingleton(Container $container): void
FILE: tests/di/Fake/Annotation/FakeInjectOne.php
class FakeInjectOne (line 11) | #[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_PARAMETER), Qua...
method isOptional (line 14) | public function isOptional()
FILE: tests/di/Fake/Annotation/FakeLeft.php
class FakeLeft (line 10) | #[Attribute, Qualifier]
FILE: tests/di/Fake/Annotation/FakeNotQualifer.php
class FakeNotQualifer (line 10) | #[Attribute]
FILE: tests/di/Fake/Annotation/FakeQualifierOnly.php
class FakeQualifierOnly (line 13) | #[Attribute(Attribute::TARGET_METHOD), Qualifier]
FILE: tests/di/Fake/Annotation/FakeRight.php
class FakeRight (line 10) | #[Attribute, Qualifier]
FILE: tests/di/Fake/FakeAbstractClass.php
class FakeAbstractClass (line 7) | abstract class FakeAbstractClass
FILE: tests/di/Fake/FakeAbstractDb.php
class FakeAbstractDb (line 7) | class FakeAbstractDb
method __construct (line 11) | public function __construct($id)
FILE: tests/di/Fake/FakeAnnoClass.php
class FakeAnnoClass (line 9) | #[Attribute(Attribute::TARGET_CLASS)]
FILE: tests/di/Fake/FakeAnnoInterceptor1.php
class FakeAnnoInterceptor1 (line 10) | class FakeAnnoInterceptor1 implements MethodInterceptor
method invoke (line 12) | public function invoke(MethodInvocation $invocation)
FILE: tests/di/Fake/FakeAnnoInterceptor2.php
class FakeAnnoInterceptor2 (line 10) | class FakeAnnoInterceptor2 implements MethodInterceptor
method invoke (line 12) | public function invoke(MethodInvocation $invocation)
FILE: tests/di/Fake/FakeAnnoInterceptor3.php
class FakeAnnoInterceptor3 (line 10) | class FakeAnnoInterceptor3 implements MethodInterceptor
method invoke (line 12) | public function invoke(MethodInvocation $invocation)
FILE: tests/di/Fake/FakeAnnoInterceptor4.php
class FakeAnnoInterceptor4 (line 10) | class FakeAnnoInterceptor4 implements MethodInterceptor
method invoke (line 12) | public function invoke(MethodInvocation $invocation)
FILE: tests/di/Fake/FakeAnnoInterceptor5.php
class FakeAnnoInterceptor5 (line 10) | class FakeAnnoInterceptor5 implements MethodInterceptor
method invoke (line 12) | public function invoke(MethodInvocation $invocation)
FILE: tests/di/Fake/FakeAnnoInterceptorInterface.php
type FakeAnnoInterceptorInterface (line 10) | interface FakeAnnoInterceptorInterface extends MethodInterceptor
FILE: tests/di/Fake/FakeAnnoMethod1.php
class FakeAnnoMethod1 (line 9) | #[Attribute(Attribute::TARGET_METHOD)]
FILE: tests/di/Fake/FakeAnnoMethod2.php
class FakeAnnoMethod2 (line 9) | #[Attribute(Attribute::TARGET_METHOD)]
FILE: tests/di/Fake/FakeAnnoMethod3.php
class FakeAnnoMethod3 (line 9) | #[Attribute(Attribute::TARGET_METHOD)]
FILE: tests/di/Fake/FakeAnnoModule.php
class FakeAnnoModule (line 7) | class FakeAnnoModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeAnnoOrderClass.php
class FakeAnnoOrderClass (line 7) | #[FakeAnnoClass]
method get (line 10) | #[FakeAnnoMethod1]
FILE: tests/di/Fake/FakeAop.php
class FakeAop (line 7) | class FakeAop implements FakeAopInterface
method returnSame (line 9) | public function returnSame($a)
FILE: tests/di/Fake/FakeAopDoublyInstallModule.php
class FakeAopDoublyInstallModule (line 7) | class FakeAopDoublyInstallModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeAopGrapher.php
class FakeAopGrapher (line 7) | class FakeAopGrapher implements FakeAopInterface
method __construct (line 11) | public function __construct($a)
method returnSame (line 16) | public function returnSame($a)
FILE: tests/di/Fake/FakeAopGrapherModule.php
class FakeAopGrapherModule (line 7) | class FakeAopGrapherModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeAopInstallModule.php
class FakeAopInstallModule (line 7) | class FakeAopInstallModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeAopInterceptorModule.php
class FakeAopInterceptorModule (line 7) | class FakeAopInterceptorModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeAopInterface.php
type FakeAopInterface (line 7) | interface FakeAopInterface
method returnSame (line 9) | public function returnSame($a);
FILE: tests/di/Fake/FakeAopInterfaceModule.php
class FakeAopInterfaceModule (line 7) | class FakeAopInterfaceModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeAopModule.php
class FakeAopModule (line 7) | class FakeAopModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeAssistedConsumer.php
class FakeAssistedConsumer (line 10) | class FakeAssistedConsumer
method assistOne (line 15) | public function assistOne($a, $b, #[Assisted] ?FakeRobotInterface $rob...
method assistWithName (line 22) | public function assistWithName($a, #[Assisted] #[Named('one')] $var1 =...
method assistAny (line 33) | public function assistAny(#[Assisted] #[Named('one')] $var2 = null, #[...
FILE: tests/di/Fake/FakeAssistedDb.php
class FakeAssistedDb (line 7) | class FakeAssistedDb extends FakeAbstractDb
FILE: tests/di/Fake/FakeAssistedDbModule.php
class FakeAssistedDbModule (line 7) | class FakeAssistedDbModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeAssistedDbProvider.php
class FakeAssistedDbProvider (line 7) | class FakeAssistedDbProvider implements ProviderInterface
method __construct (line 12) | public function __construct(MethodInvocationProvider $invocationProvider)
method get (line 17) | public function get()
FILE: tests/di/Fake/FakeAssistedInjectConsumer.php
class FakeAssistedInjectConsumer (line 12) | class FakeAssistedInjectConsumer
method assistOne (line 14) | public function assistOne($a, $b, #[Assisted] ?FakeRobotInterface $rob...
method assistWithName (line 21) | public function assistWithName($a, #[Assisted, Named('one')] $var1 = n...
method assistAny (line 32) | public function assistAny(#[Assisted, Named('one')] $var2 = null, #[In...
method assistCustomeAssistedInject (line 37) | public function assistCustomeAssistedInject(#[FakeInjectOne] int $one ...
FILE: tests/di/Fake/FakeAssistedInjectDb.php
class FakeAssistedInjectDb (line 10) | class FakeAssistedInjectDb
method getUser (line 15) | public function getUser($id, #[Inject] ?FakeAbstractDb $db = null)
FILE: tests/di/Fake/FakeAssistedParamsConsumer.php
class FakeAssistedParamsConsumer (line 9) | class FakeAssistedParamsConsumer
method getUser (line 14) | public function getUser($id, #[Assisted] ?FakeAbstractDb $db = null)
FILE: tests/di/Fake/FakeBcConstructorQualifierClass.php
class FakeBcConstructorQualifierClass (line 9) | class FakeBcConstructorQualifierClass
method __construct (line 15) | #[FakeQualifierOnly]
FILE: tests/di/Fake/FakeBcParameterQualifierClass.php
class FakeBcParameterQualifierClass (line 10) | class FakeBcParameterQualifierClass
method setSingleParam (line 23) | #[FakeInjectOne]
method setMultipleParams (line 32) | #[FakeGearStickInject('test')]
method setSingleParamWithQualifier (line 42) | #[FakeGearStickInject('test')]
method setSingleParamWithInjectOnly (line 51) | #[Inject]
method setSingleParamNoInject (line 60) | public function setSingleParamNoInject(FakeGearStickInterface $param):...
method setSingleParamMethodOnly (line 69) | #[FakeGearStickInject('test')]
FILE: tests/di/Fake/FakeBcParameterQualifierModule.php
class FakeBcParameterQualifierModule (line 9) | class FakeBcParameterQualifierModule extends AbstractModule
method configure (line 11) | protected function configure(): void
FILE: tests/di/Fake/FakeBuiltin.php
class FakeBuiltin (line 7) | class FakeBuiltin
method __construct (line 11) | public function __construct(InjectorInterface $Injector)
FILE: tests/di/Fake/FakeCar.php
class FakeCar (line 11) | class FakeCar implements FakeCarInterface
method __construct (line 29) | public function __construct(FakeEngineInterface $engine)
method setTires (line 34) | #[Inject]
method setHardtop (line 41) | #[Inject(optional: true)]
method setMirrors (line 47) | #[Inject]
method setSpareMirror (line 54) | #[Inject]
method setHandle (line 60) | #[Inject]
method setGearStick (line 66) | #[FakeGearStickInject('leather')]
method postConstruct (line 72) | #[PostConstruct]
FILE: tests/di/Fake/FakeCarEngine.php
class FakeCarEngine (line 7) | class FakeCarEngine extends FakeEngine
FILE: tests/di/Fake/FakeCarEngineModule.php
class FakeCarEngineModule (line 7) | class FakeCarEngineModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeCarInterface.php
type FakeCarInterface (line 7) | interface FakeCarInterface
FILE: tests/di/Fake/FakeCarModule.php
class FakeCarModule (line 9) | class FakeCarModule extends AbstractModule
method configure (line 11) | protected function configure()
FILE: tests/di/Fake/FakeClassInstanceBindModule.php
class FakeClassInstanceBindModule (line 7) | class FakeClassInstanceBindModule extends AbstractModule
method __construct (line 11) | public function __construct($object)
method configure (line 17) | protected function configure()
FILE: tests/di/Fake/FakeClassWithBcParameterQualifier.php
class FakeClassWithBcParameterQualifier (line 9) | class FakeClassWithBcParameterQualifier
method setGearStick (line 17) | #[FakeInjectOne]
FILE: tests/di/Fake/FakeConcreteClass.php
class FakeConcreteClass (line 7) | class FakeConcreteClass
method __construct (line 9) | public function __construct(FakeAbstractClass $class)
FILE: tests/di/Fake/FakeConstant.php
class FakeConstant (line 10) | #[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribu...
method __construct (line 14) | public function __construct(
FILE: tests/di/Fake/FakeConstantConsumer.php
class FakeConstantConsumer (line 9) | class FakeConstantConsumer
method __construct (line 17) | public function __construct(#[FakeConstant('constant')] $constant, $de...
method setFakeConstant (line 23) | #[Inject]
method setFakeConstantWithoutVarName (line 30) | #[Inject]
FILE: tests/di/Fake/FakeConstantInterface.php
type FakeConstantInterface (line 7) | interface FakeConstantInterface
FILE: tests/di/Fake/FakeConstantModule.php
class FakeConstantModule (line 7) | class FakeConstantModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeContextualModule.php
class FakeContextualModule (line 7) | class FakeContextualModule extends AbstractModule
method __construct (line 11) | public function __construct($context)
method configure (line 17) | protected function configure()
FILE: tests/di/Fake/FakeContextualProvider.php
class FakeContextualProvider (line 7) | class FakeContextualProvider implements ProviderInterface, SetContextInt...
method setContext (line 14) | public function setContext($context)
method get (line 19) | public function get()
FILE: tests/di/Fake/FakeContextualRobot.php
class FakeContextualRobot (line 7) | class FakeContextualRobot implements FakeRobotInterface
method __construct (line 11) | public function __construct($context)
FILE: tests/di/Fake/FakeDoubleInterceptor.php
class FakeDoubleInterceptor (line 10) | class FakeDoubleInterceptor implements MethodInterceptor, FakeDoubleInte...
method invoke (line 12) | public function invoke(MethodInvocation $invocation)
FILE: tests/di/Fake/FakeDoubleInterceptorInterface.php
type FakeDoubleInterceptorInterface (line 10) | interface FakeDoubleInterceptorInterface extends MethodInterceptor
FILE: tests/di/Fake/FakeEngine.php
class FakeEngine (line 7) | class FakeEngine implements FakeEngineInterface
method foo (line 9) | public function foo()
FILE: tests/di/Fake/FakeEngine2.php
class FakeEngine2 (line 7) | class FakeEngine2 implements FakeEngineInterface
method foo (line 9) | public function foo()
FILE: tests/di/Fake/FakeEngine3.php
class FakeEngine3 (line 7) | class FakeEngine3 implements FakeEngineInterface
method foo (line 9) | public function foo()
FILE: tests/di/Fake/FakeEngineInterface.php
type FakeEngineInterface (line 7) | interface FakeEngineInterface
method foo (line 9) | public function foo();
FILE: tests/di/Fake/FakeEngineProvider.php
class FakeEngineProvider (line 7) | class FakeEngineProvider implements ProviderInterface
method get (line 9) | public function get()
FILE: tests/di/Fake/FakeEngineToProviderModule.php
class FakeEngineToProviderModule (line 7) | class FakeEngineToProviderModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeFormerBindingHasPriorityModule.php
class FakeFormerBindingHasPriorityModule (line 7) | class FakeFormerBindingHasPriorityModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeGearStickInject.php
class FakeGearStickInject (line 11) | #[Attribute(Attribute::TARGET_METHOD)]
method isOptional (line 17) | public function isOptional()
method __construct (line 22) | public function __construct($value)
FILE: tests/di/Fake/FakeGearStickInterface.php
type FakeGearStickInterface (line 7) | interface FakeGearStickInterface
FILE: tests/di/Fake/FakeGearStickProvider.php
class FakeGearStickProvider (line 9) | class FakeGearStickProvider implements ProviderInterface
method __construct (line 14) | public function __construct(InjectionPointInterface $ip)
method get (line 19) | public function get()
FILE: tests/di/Fake/FakeHandle.php
class FakeHandle (line 7) | class FakeHandle implements FakeHandleInterface
FILE: tests/di/Fake/FakeHandleBar.php
class FakeHandleBar (line 9) | class FakeHandleBar
method setMirrors (line 14) | #[Inject]
method setLeftMirror (line 20) | #[Inject]
FILE: tests/di/Fake/FakeHandleBarQualifier.php
class FakeHandleBarQualifier (line 7) | class FakeHandleBarQualifier
method __construct (line 9) | public function __construct(
FILE: tests/di/Fake/FakeHandleInterface.php
type FakeHandleInterface (line 7) | interface FakeHandleInterface
FILE: tests/di/Fake/FakeHandleProvider.php
class FakeHandleProvider (line 10) | class FakeHandleProvider implements ProviderInterface
method __construct (line 14) | #[Inject]
method get (line 20) | public function get()
FILE: tests/di/Fake/FakeHardtop.php
class FakeHardtop (line 7) | class FakeHardtop implements FakeHardtopInterface
FILE: tests/di/Fake/FakeHardtopInterface.php
type FakeHardtopInterface (line 7) | interface FakeHardtopInterface
FILE: tests/di/Fake/FakeInjectionPoint.php
class FakeInjectionPoint (line 10) | class FakeInjectionPoint implements ProviderInterface
method __construct (line 14) | public function __construct(#[Named('aa')] ReflectionParameter $ip)
method get (line 19) | public function get()
FILE: tests/di/Fake/FakeInstallModule.php
class FakeInstallModule (line 7) | class FakeInstallModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeInstanceBindModule.php
class FakeInstanceBindModule (line 9) | class FakeInstanceBindModule extends AbstractModule
method configure (line 11) | protected function configure()
FILE: tests/di/Fake/FakeInstanceBindModule2.php
class FakeInstanceBindModule2 (line 7) | class FakeInstanceBindModule2 extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeInstanceBindModuleOneTo3.php
class FakeInstanceBindModuleOneTo3 (line 7) | class FakeInstanceBindModuleOneTo3 extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeInternalTypeModule.php
class FakeInternalTypeModule (line 11) | class FakeInternalTypeModule extends AbstractModule
method configure (line 13) | protected function configure()
FILE: tests/di/Fake/FakeInternalTypes.php
class FakeInternalTypes (line 9) | class FakeInternalTypes
method __construct (line 17) | public function __construct(
method stringId (line 31) | public function stringId(string $id): void
FILE: tests/di/Fake/FakeLeatherGearStick.php
class FakeLeatherGearStick (line 7) | class FakeLeatherGearStick implements FakeGearStickInterface
FILE: tests/di/Fake/FakeLeft.php
class FakeLeft (line 10) | #[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_PARAMETER)]
method __construct (line 14) | public function __construct(
FILE: tests/di/Fake/FakeLeftLeg.php
class FakeLeftLeg (line 7) | class FakeLeftLeg implements FakeLegInterface
FILE: tests/di/Fake/FakeLegInterface.php
type FakeLegInterface (line 7) | interface FakeLegInterface
FILE: tests/di/Fake/FakeLogStringModule.php
class FakeLogStringModule (line 9) | class FakeLogStringModule extends AbstractModule
method configure (line 11) | protected function configure()
FILE: tests/di/Fake/FakeMirrorInterface.php
type FakeMirrorInterface (line 7) | interface FakeMirrorInterface
FILE: tests/di/Fake/FakeMirrorLeft.php
class FakeMirrorLeft (line 7) | class FakeMirrorLeft implements FakeMirrorInterface
FILE: tests/di/Fake/FakeMirrorRight.php
class FakeMirrorRight (line 7) | class FakeMirrorRight implements FakeMirrorInterface
FILE: tests/di/Fake/FakeModuleInModule.php
class FakeModuleInModule (line 7) | class FakeModuleInModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeModuleInModuleOverride.php
class FakeModuleInModuleOverride (line 7) | class FakeModuleInModuleOverride extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeMultiBindingAnnotation.php
class FakeMultiBindingAnnotation (line 11) | final class FakeMultiBindingAnnotation
method __construct (line 19) | public function __construct(
FILE: tests/di/Fake/FakeMultiBindingConsumer.php
class FakeMultiBindingConsumer (line 11) | final class FakeMultiBindingConsumer
method __construct (line 17) | public function __construct(
method testValid (line 22) | public function testValid(): void
method testInvalid (line 37) | public function testInvalid(): void
FILE: tests/di/Fake/FakeOnionInterceptor2.php
class FakeOnionInterceptor2 (line 10) | class FakeOnionInterceptor2 implements MethodInterceptor
method invoke (line 12) | public function invoke(MethodInvocation $invocation)
FILE: tests/di/Fake/FakeOnionInterceptor3.php
class FakeOnionInterceptor3 (line 10) | class FakeOnionInterceptor3 implements MethodInterceptor
method invoke (line 12) | public function invoke(MethodInvocation $invocation)
FILE: tests/di/Fake/FakeOnionInterceptor4.php
class FakeOnionInterceptor4 (line 10) | class FakeOnionInterceptor4 implements MethodInterceptor
method invoke (line 12) | public function invoke(MethodInvocation $invocation)
FILE: tests/di/Fake/FakeOpenCarModule.php
class FakeOpenCarModule (line 7) | class FakeOpenCarModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeOverrideInstallModule.php
class FakeOverrideInstallModule (line 7) | class FakeOverrideInstallModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakePdoModule.php
class FakePdoModule (line 9) | class FakePdoModule extends AbstractModule
method configure (line 11) | protected function configure()
FILE: tests/di/Fake/FakePhp8Car.php
class FakePhp8Car (line 15) | class FakePhp8Car implements FakeCarInterface
method __construct (line 32) | public function __construct(FakeEngineInterface $engine, #[Named('righ...
method setTires (line 38) | #[Inject]
method setHardtop (line 45) | #[Inject(optional: true)]
method setMirrors (line 51) | #[Inject]
method setQualiferMirrors (line 58) | #[Inject]
method notQualifer (line 65) | #[Inject]
method setHandle (line 75) | #[Inject]
method setGearStick (line 83) | #[FakeGearStickInject('leather')]
method postConstruct (line 89) | #[PostConstruct]
method setOne (line 99) | #[Inject]
FILE: tests/di/Fake/FakePhp8CarModule.php
class FakePhp8CarModule (line 11) | class FakePhp8CarModule extends AbstractModule
method configure (line 13) | protected function configure()
FILE: tests/di/Fake/FakePhp8HandleProvider.php
class FakePhp8HandleProvider (line 10) | class FakePhp8HandleProvider implements ProviderInterface
method __construct (line 14) | public function __construct(#[Named('logo')] $logo = 'nardi')
method get (line 19) | public function get()
FILE: tests/di/Fake/FakePriorityModule.php
class FakePriorityModule (line 7) | class FakePriorityModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakePropConstruct.php
class FakePropConstruct (line 9) | class FakePropConstruct
method __construct (line 11) | public function __construct(
FILE: tests/di/Fake/FakeRenameModule.php
class FakeRenameModule (line 7) | class FakeRenameModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeRight.php
class FakeRight (line 10) | #[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_PARAMETER)]
method __construct (line 14) | public function __construct(
FILE: tests/di/Fake/FakeRightLeg.php
class FakeRightLeg (line 7) | class FakeRightLeg implements FakeLegInterface
FILE: tests/di/Fake/FakeRobot.php
class FakeRobot (line 7) | class FakeRobot implements FakeRobotInterface
FILE: tests/di/Fake/FakeRobotInterface.php
type FakeRobotInterface (line 7) | interface FakeRobotInterface
FILE: tests/di/Fake/FakeRobotProvider.php
class FakeRobotProvider (line 7) | class FakeRobotProvider implements ProviderInterface
method get (line 9) | public function get()
FILE: tests/di/Fake/FakeRobotTeam.php
class FakeRobotTeam (line 7) | class FakeRobotTeam
method __construct (line 12) | public function __construct(FakeRobot $robot1, FakeRobot $robot2)
FILE: tests/di/Fake/FakeSet.php
class FakeSet (line 10) | final class FakeSet
method __construct (line 15) | public function __construct(#[Set(FakeEngineInterface::class)] public ...
method warn (line 20) | public function warn(): void
FILE: tests/di/Fake/FakeSetNotFoundWithMap.php
class FakeSetNotFoundWithMap (line 11) | final class FakeSetNotFoundWithMap
method __construct (line 24) | public function __construct(
FILE: tests/di/Fake/FakeSetNotFoundWithProvider.php
class FakeSetNotFoundWithProvider (line 11) | final class FakeSetNotFoundWithProvider
method __construct (line 19) | public function __construct(
FILE: tests/di/Fake/FakeToBindInvalidClassModule.php
class FakeToBindInvalidClassModule (line 7) | class FakeToBindInvalidClassModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeToBindModule.php
class FakeToBindModule (line 7) | class FakeToBindModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeToBindSingletonModule.php
class FakeToBindSingletonModule (line 7) | class FakeToBindSingletonModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeToConstructorRobot.php
class FakeToConstructorRobot (line 7) | class FakeToConstructorRobot implements FakeRobotInterface
method __construct (line 13) | public function __construct(FakeLegInterface $leg, $tmpDir)
method setEngine (line 19) | public function setEngine(FakeEngineInterface $engine): void
FILE: tests/di/Fake/FakeToProviderBindModule.php
class FakeToProviderBindModule (line 7) | class FakeToProviderBindModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeToProviderSingletonBindModule.php
class FakeToProviderSingletonBindModule (line 7) | class FakeToProviderSingletonBindModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakeTyre.php
class FakeTyre (line 7) | class FakeTyre implements FakeTyreInterface
FILE: tests/di/Fake/FakeTyreInterface.php
type FakeTyreInterface (line 7) | interface FakeTyreInterface
FILE: tests/di/Fake/FakeUnNamedClass.php
class FakeUnNamedClass (line 7) | class FakeUnNamedClass
method __construct (line 9) | public function __construct(string $value)
FILE: tests/di/Fake/FakeUnNamedModule.php
class FakeUnNamedModule (line 7) | class FakeUnNamedModule extends AbstractModule
method configure (line 9) | protected function configure(): void
FILE: tests/di/Fake/FakeUntarget.php
class FakeUntarget (line 11) | class FakeUntarget
method __construct (line 15) | public function __construct(FakeUntargetChild $child)
FILE: tests/di/Fake/FakeUntargetChild.php
class FakeUntargetChild (line 11) | class FakeUntargetChild
method __construct (line 15) | public function __construct($val)
FILE: tests/di/Fake/FakeUntargetModule.php
class FakeUntargetModule (line 11) | class FakeUntargetModule extends AbstractModule
method configure (line 13) | protected function configure()
FILE: tests/di/Fake/FakeUntargetToIntanceModule.php
class FakeUntargetToIntanceModule (line 11) | class FakeUntargetToIntanceModule extends AbstractModule
method configure (line 13) | protected function configure()
FILE: tests/di/Fake/FakeWalkRobot.php
class FakeWalkRobot (line 7) | #[FakeConstant('class_constant_val')]
method __construct (line 16) | #[FakeConstant(10)]
FILE: tests/di/Fake/FakeWalkRobotLegProvider.php
class FakeWalkRobotLegProvider (line 9) | class FakeWalkRobotLegProvider implements ProviderInterface
method __construct (line 14) | public function __construct(InjectionPointInterface $ip)
method get (line 19) | public function get()
FILE: tests/di/Fake/FakeWalkRobotModule.php
class FakeWalkRobotModule (line 7) | class FakeWalkRobotModule extends AbstractModule
method configure (line 9) | protected function configure()
FILE: tests/di/Fake/FakelNoConstructorCallModule.php
class FakelNoConstructorCallModule (line 7) | class FakelNoConstructorCallModule extends AbstractModule
method __construct (line 9) | public function __construct()
method configure (line 13) | public function configure()
FILE: tests/di/Fake/NullVisitor.php
class NullVisitor (line 10) | final class NullVisitor implements VisitorInterface
method visitDependency (line 13) | public function visitDependency(
method visitProvider (line 24) | public function visitProvider(
method visitInstance (line 33) | public function visitInstance($value)
method visitAspectBind (line 39) | public function visitAspectBind(Bind $aopBind)
method visitNewInstance (line 45) | public function visitNewInstance(
method visitSetterMethods (line 61) | public function visitSetterMethods(
method visitSetterMethod (line 70) | public function visitSetterMethod(string $method, Arguments $arguments)
method visitArguments (line 76) | public function visitArguments(array $arguments)
method visitArgument (line 84) | public function visitArgument(
FILE: tests/di/GrapherTest.php
class GrapherTest (line 16) | class GrapherTest extends TestCase
method testNew (line 18) | public function testNew(): void
method testGetInstanceWithArgs (line 24) | public function testGetInstanceWithArgs(): void
method testAopClassAutoloader (line 32) | public function testAopClassAutoloader(): void
FILE: tests/di/InjectionPointTest.php
class InjectionPointTest (line 10) | class InjectionPointTest extends TestCase
method setUp (line 18) | protected function setUp(): void
method testGetParameter (line 24) | public function testGetParameter(): void
method testGetMethod (line 30) | public function testGetMethod(): void
method testGetClass (line 36) | public function testGetClass(): void
method testGetQualifiers (line 42) | public function testGetQualifiers(): void
FILE: tests/di/InjectionPointsTest.php
class InjectionPointsTest (line 11) | class InjectionPointsTest extends TestCase
method setUp (line 16) | protected function setUp(): void
method testNew (line 22) | public function testNew(): void
method testInvoke (line 27) | public function testInvoke(): SetterMethods
method testSetterMethod (line 39) | public function testSetterMethod(SetterMethods $setterMethod): void
method testSetterMethodOptional (line 52) | public function testSetterMethodOptional(SetterMethods $setterMethod):...
FILE: tests/di/InjectorTest.php
class InjectorTest (line 23) | class InjectorTest extends TestCase
method testNew (line 25) | public function testNew(): void
method testGetToInstance (line 31) | public function testGetToInstance(): void
method testToInstance (line 38) | public function testToInstance(): void
method testUnbound (line 45) | public function testUnbound(): void
method testInstall (line 52) | public function testInstall(): void
method testFormerBindingHasPriority (line 61) | public function testFormerBindingHasPriority(): void
method testLatterBindingHasPriorityWithThisParameter (line 68) | public function testLatterBindingHasPriorityWithThisParameter(): void
method testModuleInModule (line 75) | public function testModuleInModule(): void
method testModuleInModuleOverride (line 84) | public function testModuleInModuleOverride(): void
method testToBinding (line 91) | public function testToBinding(): void
method testClassToClassBinding (line 98) | public function testClassToClassBinding(): void
method testToBindingPrototype (line 105) | public function testToBindingPrototype(): void
method testToBindingSingleton (line 113) | public function testToBindingSingleton(): void
method testToProviderBinding (line 121) | public function testToProviderBinding(): void
method testClassToProviderBinding (line 129) | public function testClassToProviderBinding(): void
method testToProviderBindingSingleton (line 136) | public function testToProviderBindingSingleton(): void
method testGetConcreteClass (line 144) | public function testGetConcreteClass(): void
method testGetConcreteHavingDependency (line 151) | public function testGetConcreteHavingDependency(): void
method testGetConcreteClassWithModule (line 165) | public function testGetConcreteClassWithModule(): void
method testAnnotationBasedInjection (line 172) | public function testAnnotationBasedInjection(): Injector
method testSerialize (line 193) | public function testSerialize(Injector $injector): void
method testAop (line 201) | public function testAop(): void
method testIntefaceBindingAop (line 210) | public function testIntefaceBindingAop(): void
method testBuiltinBinding (line 231) | public function testBuiltinBinding(): void
method testSerializeBuiltinBinding (line 237) | public function testSerializeBuiltinBinding(): void
method testAopBoundInDifferentModule (line 245) | public function testAopBoundInDifferentModule(): void
method testAopBoundInDifferentModuleAfterAnotherBinding (line 254) | public function testAopBoundInDifferentModuleAfterAnotherBinding(): void
method testAopBoundDoublyInDifferentModule (line 263) | public function testAopBoundDoublyInDifferentModule(): void
method testAopClassAutoloader (line 272) | public function testAopClassAutoloader(): void
method testAopOnDemandByUnboundConcreteClass (line 293) | public function testAopOnDemandByUnboundConcreteClass(): void
method testBindOrder (line 301) | public function testBindOrder(): void
method testAnnotateConstant (line 310) | public function testAnnotateConstant(): void
method testContextualDependencyInjection (line 316) | public function testContextualDependencyInjection(): void
method testNewAbstract (line 324) | public function testNewAbstract(): void
method testIsOptionalValue (line 331) | public function testIsOptionalValue(): void
method testInternalTypes (line 339) | public function testInternalTypes(): void
method testToConstructor (line 347) | public function testToConstructor(): void
method testNullObject (line 364) | public function testNullObject(): void
method testBindInterfeceInterceptor (line 376) | public function testBindInterfeceInterceptor(): void
method testBindInterfeceNullInterceptor (line 395) | public function testBindInterfeceNullInterceptor(): void
method testModuleArray (line 415) | public function testModuleArray(): void
method testSingleArray (line 441) | public function testSingleArray(): void
method testProviderInjectWithSet (line 460) | public function testProviderInjectWithSet(): void
FILE: tests/di/ModuleMergerTest.php
class ModuleMergerTest (line 9) | class ModuleMergerTest extends TestCase
method testInvoke (line 11) | public function testInvoke(): void
FILE: tests/di/ModuleTest.php
class ModuleTest (line 12) | class ModuleTest extends TestCase
method testNew (line 14) | public function testNew(): void
method testInstall (line 20) | public function testInstall(): void
method testToInvalidClass (line 26) | public function testToInvalidClass(): void
method testRename (line 32) | public function testRename(): void
method testConstructorCallModule (line 39) | public function testConstructorCallModule(): void
method testActivate (line 46) | public function testActivate(): void
method testtoString (line 52) | public function testtoString(): void
FILE: tests/di/MultiBinding/MultiBinderTest.php
class MultiBinderTest (line 17) | class MultiBinderTest extends TestCase
method testAdd (line 19) | public function testAdd(): void
method testSet (line 31) | public function testSet(): void
FILE: tests/di/MultiBinding/MultiBindingModuleTest.php
class MultiBindingModuleTest (line 32) | class MultiBindingModuleTest extends TestCase
method setUp (line 37) | protected function setUp(): void
method testInjectMap (line 57) | public function testInjectMap(): Map
method testMapInstance (line 71) | public function testMapInstance(Map $map): void
method testMapIteration (line 82) | public function testMapIteration(Map $map): void
method testIsSet (line 94) | public function testIsSet(Map $map): void
method testOffsetSet (line 105) | public function testOffsetSet(Map $map): void
method testOffsetUnset (line 116) | public function testOffsetUnset(Map $map): void
method testAnotherBinder (line 122) | public function testAnotherBinder(): void
method testMultipileModule (line 131) | public function testMultipileModule(): void
method testAnnotation (line 153) | public function testAnnotation(): void
method testSetNotFoundInMap (line 163) | public function testSetNotFoundInMap(): void
method testSetNotFoundInProvider (line 170) | public function testSetNotFoundInProvider(): void
FILE: tests/di/NameTest.php
class NameTest (line 10) | class NameTest extends TestCase
method testUnName (line 12) | public function testUnName(): void
method testSingleName (line 20) | public function testSingleName(): void
method testSetName (line 28) | public function testSetName(): void
method testKeyValuePairName (line 40) | public function testKeyValuePairName(string $keyPairValueString): void
method keyPairStringProvider (line 52) | public function keyPairStringProvider(): array
method testKeyValuePairButNotFound (line 62) | public function testKeyValuePairButNotFound(): void
method testKeyValuePairWithDollarPrefix (line 70) | public function testKeyValuePairWithDollarPrefix(): void
FILE: tests/di/NewInstanceTest.php
class NewInstanceTest (line 13) | class NewInstanceTest extends TestCase
method setUp (line 18) | protected function setUp(): void
method testInvoke (line 30) | public function testInvoke(): void
FILE: tests/di/NoHintTest.php
class NoHintTest (line 11) | class NoHintTest extends TestCase
method testNoHintIsUnbound (line 13) | public function testNoHintIsUnbound(): void
method testNoHintThrownForNoTypeNoName (line 19) | public function testNoHintThrownForNoTypeNoName(): void
method testNoHintMessageFormat (line 27) | public function testNoHintMessageFormat(): void
FILE: tests/di/NullModuleTest.php
class NullModuleTest (line 9) | class NullModuleTest extends TestCase
method testEmpty (line 11) | public function testEmpty(): void
FILE: tests/di/ProviderProviderTest.php
class ProviderProviderTest (line 10) | class ProviderProviderTest extends TestCase
method testGet (line 12) | public function testGet(): void
FILE: tests/di/SetterMethodTest.php
class SetterMethodTest (line 15) | class SetterMethodTest extends TestCase
method setUp (line 20) | protected function setUp(): void
method testInvoke (line 27) | public function testInvoke(): void
method testUnbound (line 39) | public function testUnbound(): void
method testAcceptWithUnboundException (line 47) | public function testAcceptWithUnboundException(): void
method testAcceptWithUnboundExceptionOptional (line 102) | public function testAcceptWithUnboundExceptionOptional(): void
FILE: tests/di/SetterMethodsTest.php
class SetterMethodsTest (line 10) | class SetterMethodsTest extends TestCase
method setUp (line 15) | protected function setUp(): void
method testInvoke (line 21) | public function testInvoke(): void
FILE: tests/di/SpyCompilerTest.php
class SpyCompilerTest (line 10) | class SpyCompilerTest extends TestCase
method testNoBindng (line 12) | public function testNoBindng(): void
FILE: tests/di/UnboundTest.php
class UnboundTest (line 11) | class UnboundTest extends TestCase
method testGetBound (line 13) | public function testGetBound(): void
method testNoPrevious (line 23) | public function testNoPrevious(): void
method testNonUnboundPrevious (line 30) | public function testNonUnboundPrevious(): void
FILE: tests/di/VisitorTest.php
class VisitorTest (line 16) | class VisitorTest extends TestCase
method setUp (line 30) | public function setUp(): void
method testNullVisit (line 43) | public function testNullVisit(): void
method testCollectVisit (line 49) | public function testCollectVisit(): void
method testVisitDependencyProvider (line 181) | public function testVisitDependencyProvider(): void
method testVisitInsntace (line 187) | public function testVisitInsntace(): void
FILE: tests/type/InjectorInterfaceTest.php
class InjectorInterfaceTest (line 10) | final class InjectorInterfaceTest
method __construct (line 16) | public function __construct()
Condensed preview — 311 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (317K chars).
[
{
"path": ".gitattributes",
"chars": 702,
"preview": "# Normalize line endings\n* text=auto eol=lf\n\n/tests export-ignore\n/tests-php8 export-ignore\n/demo "
},
{
"path": ".github/CONTRIBUTING.md",
"chars": 723,
"preview": "# CONTRIBUTING\n\n## Code Contributions\n\n## Installation\n\nInstall project dependencies and test tools by running the follo"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 284,
"preview": "---\nname: Bug Report\nabout: Create a bug report\nlabels: Bug\n---\n\n### Bug Report\n\n<!-- Provide a summary describing the p"
},
{
"path": ".github/ISSUE_TEMPLATE/feature.md",
"chars": 120,
"preview": "---\nname: Feature\nabout: Suggest a new feature or enhancement\nlabels: Feature\n---\n\n<!-- Write your suggestion here. -->\n"
},
{
"path": ".github/ISSUE_TEMPLATE/question.md",
"chars": 122,
"preview": "---\nname: Question\nabout: Ask a question regarding software usage\nlabels: Support\n---\n\n<!-- Write your question here. --"
},
{
"path": ".github/SECURITY.md",
"chars": 200,
"preview": "# Reporting a vulnerability\n\nIf you have found any issues that might have security implications,\nplease send a report pr"
},
{
"path": ".github/workflows/coding-standards.yml",
"chars": 186,
"preview": "name: Coding Standards\n\non:\n push:\n pull_request:\n workflow_dispatch:\n\njobs:\n cs:\n uses: ray-di/.github/.github/w"
},
{
"path": ".github/workflows/continuous-integration.yml",
"chars": 270,
"preview": "name: Continuous Integration\n\non:\n push:\n pull_request:\n workflow_dispatch:\n\njobs:\n ci:\n uses: ray-di/.github/.gi"
},
{
"path": ".github/workflows/demo.yml",
"chars": 917,
"preview": "name: Demo\n\non:\n push:\n pull_request:\n workflow_dispatch:\n\njobs:\n demo:\n name: Demo\n runs-on: ubuntu-latest\n "
},
{
"path": ".github/workflows/prefer-lowest.yml",
"chars": 957,
"preview": "name: Prefer Lowest\n\non:\n push:\n pull_request:\n workflow_dispatch:\n\njobs:\n prefer-lowest:\n name: Prefer Lowest\n "
},
{
"path": ".github/workflows/static-analysis.yml",
"chars": 184,
"preview": "name: Static Analysis\n\non:\n push:\n pull_request:\n workflow_dispatch:\n\njobs:\n sa:\n uses: ray-di/.github/.github/wo"
},
{
"path": ".github/workflows/update-copyright-years-in-license-file.yml",
"chars": 353,
"preview": "name: Update copyright year(s) in license file\n\non:\n workflow_dispatch:\n schedule:\n - cron: \"0 3 1 1 *\"\n\njobs:\n ru"
},
{
"path": ".gitignore",
"chars": 414,
"preview": "/vendor/\n/build/\n/tests/compiler/tmp/car/\n/tests/compiler/tmp/injector_cache/\n/tests/compiler/tmp/logger/\n/tests/compile"
},
{
"path": ".scrutinizer.yml",
"chars": 212,
"preview": "build:\n image: default-jammy\n environment:\n php: 8.4\n nodes:\n analysis:\n tests:\n "
},
{
"path": ".sonarcloud.properties",
"chars": 221,
"preview": "# Exclude files from SonarCloud analysis\n# - GitHub workflow files: version tags are best practice\n# - Demo files: examp"
},
{
"path": "CLAUDE.md",
"chars": 3126,
"preview": "# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## "
},
{
"path": "LICENSE",
"chars": 1087,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2012-2026 Akihito Koriyama\n\nPermission is hereby granted, free of charge, to any pe"
},
{
"path": "README.md",
"chars": 981,
"preview": "# Ray.Di\n\n## A dependency injection framework for PHP\n\n[;\n\nuse Ray\\Di\\AbstractModule;\nuse Ray\\Di\\Injector;\n\nrequire dirname(__DIR__) . '/vendor/au"
},
{
"path": "demo/01b-linked-binding-setter-injection.php",
"chars": 969,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Ray\\Di\\AbstractModule;\nuse Ray\\Di\\Di\\Inject;\nuse Ray\\Di\\Injector;\n\nrequire dirname("
},
{
"path": "demo/02-provider-binding.php",
"chars": 1268,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Ray\\Di\\AbstractModule;\nuse Ray\\Di\\Injector;\nuse Ray\\Di\\ProviderInterface;\n\nrequire "
},
{
"path": "demo/02a-named-by-qualifier.php",
"chars": 1089,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Ray\\Di\\AbstractModule;\nuse Ray\\Di\\Di\\Qualifier;\nuse Ray\\Di\\Injector;\n\nrequire dirna"
},
{
"path": "demo/02b-named-by-named.php",
"chars": 1010,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Ray\\Di\\AbstractModule;\nuse Ray\\Di\\Di\\Named;\nuse Ray\\Di\\Injector;\n\nrequire dirname(_"
},
{
"path": "demo/03-injection-point.php",
"chars": 1615,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Ray\\Di\\AbstractModule;\nuse Ray\\Di\\InjectionPointInterface;\nuse Ray\\Di\\Injector;\nuse"
},
{
"path": "demo/04-untarget-binding.php",
"chars": 595,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Ray\\Di\\AbstractModule;\nuse Ray\\Di\\Injector;\nuse Ray\\Di\\Scope;\n\nrequire dirname(__DI"
},
{
"path": "demo/05a-constructor-binding.php",
"chars": 1150,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nrequire dirname(__DIR__) . '/vendor/autoload.php';\n\nuse Ray\\Di\\AbstractModule;\nuse Ray\\"
},
{
"path": "demo/05b-constructor-binding-setter-injection.php",
"chars": 1256,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Demo;\n\nuse Ray\\Di\\AbstractModule;\nuse Ray\\Di\\InjectionPoints;\nuse Ray\\"
},
{
"path": "demo/07-assisted-injection.php",
"chars": 656,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Composer\\Autoload\\ClassLoader;\nuse Ray\\Di\\AbstractModule;\nuse Ray\\Di\\Injector;\n\n$lo"
},
{
"path": "demo/10-cache.php",
"chars": 1008,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Composer\\Autoload\\ClassLoader;\nuse Ray\\Di\\Injector;\n\n$loader = require dirname(__DI"
},
{
"path": "demo/11-script-injector.php",
"chars": 1140,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Composer\\Autoload\\ClassLoader;\nuse Ray\\Compiler\\DiCompiler;\nuse Ray\\Compiler\\Script"
},
{
"path": "demo/12-dependency-chain-error-message.php",
"chars": 2412,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Composer\\Autoload\\ClassLoader;\nuse Ray\\Di\\AbstractModule;\nuse Ray\\Di\\Exception\\Unbo"
},
{
"path": "demo/chain-error/A.php",
"chars": 95,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nclass A\n{\n public function __construct(B $b)\n {\n }\n}\n"
},
{
"path": "demo/chain-error/B.php",
"chars": 95,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nclass B\n{\n public function __construct(C $c)\n {\n }\n}\n"
},
{
"path": "demo/chain-error/C.php",
"chars": 95,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nclass C\n{\n public function __construct(D $d)\n {\n }\n}\n"
},
{
"path": "demo/chain-error/D.php",
"chars": 104,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nclass D\n{\n public function __construct(EInterface $e)\n {\n }\n}\n"
},
{
"path": "demo/chain-error/EInterface.php",
"chars": 58,
"preview": "<?php\n\ndeclare(strict_types=1);\n\ninterface EInterface\n{\n}\n"
},
{
"path": "demo/finder/Db.php",
"chars": 232,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Ray\\Di\\Di\\PostConstruct;\n\nclass Db implements DbInterface\n{\n public function __c"
},
{
"path": "demo/finder/DbFinder.php",
"chars": 322,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Ray\\Di\\Di\\Inject;\n\nclass DbFinder implements FinderInterface\n{\n public function "
},
{
"path": "demo/finder/DbInterface.php",
"chars": 59,
"preview": "<?php\n\ndeclare(strict_types=1);\n\ninterface DbInterface\n{\n}\n"
},
{
"path": "demo/finder/Finder.php",
"chars": 77,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nclass Finder implements FinderInterface\n{\n}\n"
},
{
"path": "demo/finder/FinderInterface.php",
"chars": 63,
"preview": "<?php\n\ndeclare(strict_types=1);\n\ninterface FinderInterface\n{\n}\n"
},
{
"path": "demo/finder/FinderModule.php",
"chars": 712,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Ray\\Di\\AbstractModule;\nuse Ray\\Di\\Scope;\n\nclass FinderModule extends AbstractModule"
},
{
"path": "demo/finder/MovieFinder.php",
"chars": 266,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Ray\\Di\\Di\\Assisted;\nuse Ray\\Di\\Di\\Inject;\n\nclass MovieFinder\n{\n public function "
},
{
"path": "demo/finder/MovieLister.php",
"chars": 315,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Ray\\Di\\Di\\Inject;\n\nclass MovieLister implements MovieListerInterface\n{\n public f"
},
{
"path": "demo/finder/MovieListerInterface.php",
"chars": 68,
"preview": "<?php\n\ndeclare(strict_types=1);\n\ninterface MovieListerInterface\n{\n}\n"
},
{
"path": "demo/finder/Sorter.php",
"chars": 50,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nclass Sorter\n{\n}\n"
},
{
"path": "demo/run.php",
"chars": 858,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nputenv('TMPDIR=' . __DIR__ . '/tmp');\n\npassthru('php ' . __DIR__ . '/01a-linked-binding"
},
{
"path": "demo/tmp/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "phpcs.xml",
"chars": 4146,
"preview": "<?xml version=\"1.0\"?>\n<ruleset\n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" name=\"bearcs\"\n xsi:noNamespa"
},
{
"path": "phpmd.xml",
"chars": 2070,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ruleset name=\"PHPMD rule set\"\n xmlns=\"http://pmd.sf.net/ruleset/1.0.0\"\n "
},
{
"path": "phpstan.neon",
"chars": 421,
"preview": "parameters:\n errorFormat: raw\n level: max\n paths:\n - src/di\n - tests/di\n - tests/type\n excludePaths:\n - "
},
{
"path": "phpunit.xml.dist",
"chars": 738,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit\n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n xs"
},
{
"path": "psalm.xml",
"chars": 537,
"preview": "<?xml version=\"1.0\"?>\n<psalm\n errorLevel=\"1\"\n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n xmlns=\"htt"
},
{
"path": "rector.php",
"chars": 544,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Rector\\Config\\RectorConfig;\nuse Rector\\Set\\ValueObject\\LevelSetList;\nuse Rector\\Set"
},
{
"path": "src/di/AbstractModule.php",
"chars": 4267,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\AbstractMatcher;\nuse Ray\\Aop\\Matcher;\nuse Ray\\Aop\\Pointc"
},
{
"path": "src/di/AcceptInterface.php",
"chars": 425,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\n/**\n * This interface defines the accept method, which allows an obj"
},
{
"path": "src/di/AnnotatedClass.php",
"chars": 1492,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\ReflectionClass;\nuse Ray\\Di\\Di\\PostConstruct;\nuse Reflec"
},
{
"path": "src/di/AnnotatedClassMethods.php",
"chars": 1485,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\ReflectionClass;\nuse Ray\\Aop\\ReflectionMethod;\nuse Ray\\D"
},
{
"path": "src/di/Annotation/ScriptDir.php",
"chars": 242,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Annotation;\n\nuse Attribute;\nuse Ray\\Di\\Di\\Qualifier;\n\n/**\n * Script di"
},
{
"path": "src/di/Argument.php",
"chars": 3979,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse ReflectionException;\nuse ReflectionMethod;\nuse ReflectionNamedTy"
},
{
"path": "src/di/Arguments.php",
"chars": 2602,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Di\\Exception\\NoHint;\nuse Ray\\Di\\Exception\\Unbound;\nuse Refle"
},
{
"path": "src/di/AspectBind.php",
"chars": 1276,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\Bind as AopBind;\nuse Ray\\Aop\\MethodInterceptor;\n\nuse fun"
},
{
"path": "src/di/AssistedInjectInterceptor.php",
"chars": 4035,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\MethodInterceptor;\nuse Ray\\Aop\\MethodInvocation;\nuse Ray"
},
{
"path": "src/di/AssistedInjectModule.php",
"chars": 423,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Di\\Matcher\\AssistedInjectMatcher;\n\n/**\n * Assisted module fo"
},
{
"path": "src/di/AssistedModule.php",
"chars": 725,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\MethodInvocation;\n\n/**\n * Module for assisted injection "
},
{
"path": "src/di/Bind.php",
"chars": 5086,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\MethodInterceptor;\nuse Ray\\Aop\\ReflectionClass;\nuse Refl"
},
{
"path": "src/di/BindValidator.php",
"chars": 2188,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\MethodInterceptor;\nuse Ray\\Aop\\NullInterceptor;\nuse Ray\\"
},
{
"path": "src/di/BuiltinModule.php",
"chars": 384,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Di\\MultiBinding\\MultiBindingModule;\n\nfinal class BuiltinModu"
},
{
"path": "src/di/CompileNullObject.php",
"chars": 531,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\n/**\n * Convert NullObjectDependency to Dependency\n */\nfinal class Co"
},
{
"path": "src/di/Container.php",
"chars": 5774,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse BadMethodCallException;\nuse Ray\\Aop\\Compiler;\nuse Ray\\Aop\\Compil"
},
{
"path": "src/di/ContainerFactory.php",
"chars": 1392,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\Compiler;\n\nuse function array_shift;\n\n/**\n * @psalm-impo"
},
{
"path": "src/di/Dependency.php",
"chars": 4013,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\Bind as AopBind;\nuse Ray\\Aop\\CompilerInterface;\nuse Ray\\"
},
{
"path": "src/di/DependencyFactory.php",
"chars": 1650,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\ReflectionClass;\nuse ReflectionMethod;\n\nuse function ass"
},
{
"path": "src/di/DependencyInterface.php",
"chars": 843,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\n/**\n * @psalm-import-type DependencyContainer from Types\n * @psalm-i"
},
{
"path": "src/di/DependencyProvider.php",
"chars": 2062,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse function assert;\nuse function sprintf;\n\nfinal class DependencyPr"
},
{
"path": "src/di/Di/Assisted.php",
"chars": 348,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Di;\n\nuse Attribute;\n\n/**\n * Marks a parameter for assisted injection\n "
},
{
"path": "src/di/Di/Inject.php",
"chars": 747,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Di;\n\nuse Attribute;\n\n/**\n * Annotates your class methods into which th"
},
{
"path": "src/di/Di/InjectInterface.php",
"chars": 210,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Di;\n\ninterface InjectInterface\n{\n /**\n * Whether or not to use "
},
{
"path": "src/di/Di/Named.php",
"chars": 314,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Di;\n\nuse Attribute;\n\n/**\n * Annotates named things\n *\n * @psalm-immuta"
},
{
"path": "src/di/Di/PostConstruct.php",
"chars": 769,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Di;\n\nuse Attribute;\n\n/**\n * PostConstruct\n *\n * The PostConstruct anno"
},
{
"path": "src/di/Di/Qualifier.php",
"chars": 179,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Di;\n\nuse Attribute;\n\n/**\n * Identifies qualifier annotations\n */\n#[Att"
},
{
"path": "src/di/Di/Set.php",
"chars": 371,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Di;\n\nuse Attribute;\n\n/**\n * @template T of object\n * @psalm-immutable\n"
},
{
"path": "src/di/Exception/DirectoryNotWritable.php",
"chars": 177,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Exception;\n\nuse RuntimeException;\n\nfinal class DirectoryNotWritable ex"
},
{
"path": "src/di/Exception/ExceptionInterface.php",
"chars": 95,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Exception;\n\ninterface ExceptionInterface\n{\n}\n"
},
{
"path": "src/di/Exception/InvalidContext.php",
"chars": 187,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Exception;\n\nuse InvalidArgumentException;\n\nfinal class InvalidContext "
},
{
"path": "src/di/Exception/InvalidProvider.php",
"chars": 188,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Exception;\n\nuse InvalidArgumentException;\n\nfinal class InvalidProvider"
},
{
"path": "src/di/Exception/InvalidToConstructorNameParameter.php",
"chars": 276,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Exception;\n\nuse InvalidArgumentException;\n\n/**\n * @see https://github."
},
{
"path": "src/di/Exception/InvalidType.php",
"chars": 184,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Exception;\n\nuse InvalidArgumentException;\n\nfinal class InvalidType ext"
},
{
"path": "src/di/Exception/MethodInvocationNotAvailable.php",
"chars": 123,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Exception;\n\nfinal class MethodInvocationNotAvailable extends Unbound\n{"
},
{
"path": "src/di/Exception/NoHint.php",
"chars": 392,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Exception;\n\n/**\n * Exception thrown when a parameter has no type hint "
},
{
"path": "src/di/Exception/NotFound.php",
"chars": 161,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Exception;\n\nuse LogicException;\n\nfinal class NotFound extends LogicExc"
},
{
"path": "src/di/Exception/SetNotFound.php",
"chars": 164,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Exception;\n\nuse LogicException;\n\nfinal class SetNotFound extends Logic"
},
{
"path": "src/di/Exception/Unbound.php",
"chars": 1710,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Exception;\n\nuse Exception;\nuse LogicException;\n\nuse function array_pop"
},
{
"path": "src/di/Exception/Untargeted.php",
"chars": 105,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Exception;\n\nfinal class Untargeted extends Unbound\n{\n}\n"
},
{
"path": "src/di/Exception.php",
"chars": 97,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nfinal class Exception extends \\Exception\n{\n}\n"
},
{
"path": "src/di/Grapher.php",
"chars": 1679,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\Compiler;\n\nuse function file_exists;\nuse function spl_au"
},
{
"path": "src/di/InjectableInterface.php",
"chars": 86,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\ninterface InjectableInterface\n{\n}\n"
},
{
"path": "src/di/InjectionPoint.php",
"chars": 2467,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\ReflectionClass;\nuse Ray\\Aop\\ReflectionMethod;\nuse Ray\\D"
},
{
"path": "src/di/InjectionPointInterface.php",
"chars": 759,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\ReflectionClass;\nuse Ray\\Aop\\ReflectionMethod;\nuse Refle"
},
{
"path": "src/di/InjectionPoints.php",
"chars": 1502,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse ReflectionException;\nuse ReflectionMethod;\n\n/**\n * @psalm-import"
},
{
"path": "src/di/Injector.php",
"chars": 2825,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\Compiler;\nuse Ray\\Di\\Exception\\DirectoryNotWritable;\nuse"
},
{
"path": "src/di/InjectorInterface.php",
"chars": 736,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\n/**\n * Builds the graphs of objects that make up your application\n *"
},
{
"path": "src/di/Instance.php",
"chars": 1321,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse function gettype;\nuse function is_object;\nuse function is_scalar"
},
{
"path": "src/di/Matcher/AssistedInjectMatcher.php",
"chars": 1240,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Matcher;\n\nuse LogicException;\nuse Ray\\Aop\\AbstractMatcher;\nuse Ray\\Di\\"
},
{
"path": "src/di/MethodInvocationProvider.php",
"chars": 790,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\MethodInvocation;\nuse Ray\\Di\\Exception\\MethodInvocationN"
},
{
"path": "src/di/ModuleString.php",
"chars": 1094,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse function assert;\nuse function implode;\nuse function serialize;\nu"
},
{
"path": "src/di/MultiBinder.php",
"chars": 2418,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Di\\MultiBinding\\LazyInstance;\nuse Ray\\Di\\MultiBinding\\LazyIn"
},
{
"path": "src/di/MultiBinding/LazyInstance.php",
"chars": 470,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\MultiBinding;\n\nuse Ray\\Di\\InjectorInterface;\n\n/**\n * @template T of mi"
},
{
"path": "src/di/MultiBinding/LazyInterface.php",
"chars": 220,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\MultiBinding;\n\nuse Ray\\Di\\InjectorInterface;\n\ninterface LazyInterface\n"
},
{
"path": "src/di/MultiBinding/LazyProvider.php",
"chars": 544,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\MultiBinding;\n\nuse Ray\\Di\\InjectorInterface;\nuse Ray\\Di\\ProviderInterf"
},
{
"path": "src/di/MultiBinding/LazyTo.php",
"chars": 454,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\MultiBinding;\n\nuse Ray\\Di\\InjectorInterface;\n\n/**\n * @template T of ob"
},
{
"path": "src/di/MultiBinding/Map.php",
"chars": 2119,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\MultiBinding;\n\nuse ArrayAccess;\nuse Countable;\nuse Generator;\nuse Iter"
},
{
"path": "src/di/MultiBinding/MapProvider.php",
"chars": 1037,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\MultiBinding;\n\nuse Ray\\Di\\Di\\Set;\nuse Ray\\Di\\Exception\\SetNotFound;\nus"
},
{
"path": "src/di/MultiBinding/MultiBindingModule.php",
"chars": 389,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\MultiBinding;\n\nuse Ray\\Di\\AbstractModule;\nuse Ray\\Di\\Types;\n\n/**\n * @p"
},
{
"path": "src/di/MultiBinding/MultiBindings.php",
"chars": 489,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\MultiBinding;\n\nuse ArrayObject;\nuse Ray\\Di\\Types;\n\nuse function array_"
},
{
"path": "src/di/Name.php",
"chars": 3460,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Di\\Di\\Named;\nuse Ray\\Di\\Di\\Qualifier;\nuse ReflectionAttribut"
},
{
"path": "src/di/NewInstance.php",
"chars": 2957,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\Bind as AopBind;\nuse Ray\\Aop\\WeavedInterface;\nuse Reflec"
},
{
"path": "src/di/NullDependency.php",
"chars": 624,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\n/**\n * @codeCoverageIgnore\n */\nfinal class NullDependency implements"
},
{
"path": "src/di/NullModule.php",
"chars": 155,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nfinal class NullModule extends AbstractModule\n{\n protected functi"
},
{
"path": "src/di/NullObjectDependency.php",
"chars": 1190,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Koriym\\NullObject\\NullObject;\nuse ReflectionClass;\n\nuse function"
},
{
"path": "src/di/ProviderInterface.php",
"chars": 176,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\n/**\n * @template T of mixed\n */\ninterface ProviderInterface\n{\n /*"
},
{
"path": "src/di/ProviderProvider.php",
"chars": 486,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Di\\Di\\Set;\n\n/**\n * @implements ProviderInterface<mixed>\n * @"
},
{
"path": "src/di/ProviderSetModule.php",
"chars": 249,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nfinal class ProviderSetModule extends AbstractModule\n{\n protected"
},
{
"path": "src/di/ProviderSetProvider.php",
"chars": 806,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Di\\Di\\Set;\nuse Ray\\Di\\Exception\\SetNotFound;\n\n/**\n * @implem"
},
{
"path": "src/di/Scope.php",
"chars": 237,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nfinal class Scope\n{\n /**\n * Singleton scope\n */\n publi"
},
{
"path": "src/di/SetContextInterface.php",
"chars": 236,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\ninterface SetContextInterface\n{\n /**\n * Set provider context\n"
},
{
"path": "src/di/SetterMethod.php",
"chars": 1871,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Exception;\nuse LogicException;\nuse Ray\\Di\\Exception\\Unbound;\nuse"
},
{
"path": "src/di/SetterMethods.php",
"chars": 939,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Exception;\n\n/**\n * @psalm-import-type SetterMethodsList from Typ"
},
{
"path": "src/di/SpyCompiler.php",
"chars": 2550,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse LogicException;\nuse Ray\\Aop\\BindInterface;\nuse Ray\\Aop\\CompilerI"
},
{
"path": "src/di/Types.php",
"chars": 3158,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\MethodInterceptor;\nuse Ray\\Aop\\Pointcut;\n\n/**\n * Ray.Di "
},
{
"path": "src/di/Untarget.php",
"chars": 865,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\ReflectionClass;\n\nfinal class Untarget\n{\n /**\n * "
},
{
"path": "src/di/VisitorInterface.php",
"chars": 1954,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\Bind as AopBind;\nuse ReflectionParameter;\n\n/**\n * Visits"
},
{
"path": "src-deprecated/di/BcParameterQualifier.php",
"chars": 4726,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Di\\Di\\InjectInterface;\nuse Ray\\Di\\Di\\Qualifier;\nuse Reflecti"
},
{
"path": "src-deprecated/di/BcStringParser.php",
"chars": 1299,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse function explode;\nuse function substr;\nuse function trim;\n\n/**\n "
},
{
"path": "src-deprecated/di/EmptyModule.php",
"chars": 235,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\n/**\n * @deprecated User NullModule instead\n */\nclass EmptyModule ext"
},
{
"path": "src-deprecated/di/NullCache.php",
"chars": 867,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Doctrine\\Common\\Cache\\CacheProvider;\n\n/**\n * @psalm-suppress Dep"
},
{
"path": "src-deprecated/di/Provider.php",
"chars": 155,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\n/**\n * @deprecated User ProviderInterface instead\n */\ninterface Prov"
},
{
"path": "tests/bootstrap.php",
"chars": 436,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nputenv('TMPDIR=' . __DIR__ . '/tmp');\n\nrequire_once dirname(__DIR__) . '/vendor/autoloa"
},
{
"path": "tests/di/AnnotatedClassTest.php",
"chars": 2860,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse LogicException;\nuse PHPUnit\\Framework\\TestCase;\nuse Ray\\Aop\\Refl"
},
{
"path": "tests/di/ArgumentTest.php",
"chars": 1223,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse PHPUnit\\Framework\\TestCase;\nuse ReflectionMethod;\nuse Reflection"
},
{
"path": "tests/di/ArgumentsTest.php",
"chars": 1311,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse PHPUnit\\Framework\\TestCase;\nuse ReflectionMethod;\nuse Reflection"
},
{
"path": "tests/di/AssistedTest.php",
"chars": 2392,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Ray\\Di\\Exception\\MethodInvocatio"
},
{
"path": "tests/di/BcParameterQualifierIntegrationTest.php",
"chars": 651,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse PHPUnit\\Framework\\TestCase;\n\nclass BcParameterQualifierIntegrati"
},
{
"path": "tests/di/BcParameterQualifierTest.php",
"chars": 2934,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Ray\\Di\\Annotation\\FakeInjectOne;"
},
{
"path": "tests/di/BcStringParserTest.php",
"chars": 927,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse PHPUnit\\Framework\\TestCase;\n\nclass BcStringParserTest extends Te"
},
{
"path": "tests/di/BindTest.php",
"chars": 5828,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Ray\\Di\\Exception\\InvalidProvider"
},
{
"path": "tests/di/ContainerTest.php",
"chars": 7160,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse BadMethodCallException;\nuse PHPUnit\\Framework\\TestCase;\nuse Ray\\"
},
{
"path": "tests/di/ContextualProviderTest.php",
"chars": 413,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse PHPUnit\\Framework\\TestCase;\n\nclass ContextualProviderTest extend"
},
{
"path": "tests/di/DependencyTest.php",
"chars": 5023,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Ray\\Aop\\Compiler;\nuse Ray\\Aop\\Ma"
},
{
"path": "tests/di/Fake/Annotation/FakeInjectOne.php",
"chars": 339,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Annotation;\n\nuse Attribute;\nuse Ray\\Di\\Di\\InjectInterface;\nuse Ray\\Di\\"
},
{
"path": "tests/di/Fake/Annotation/FakeLeft.php",
"chars": 153,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Annotation;\n\nuse Attribute;\nuse Ray\\Di\\Di\\Qualifier;\n\n#[Attribute, Qua"
},
{
"path": "tests/di/Fake/Annotation/FakeNotQualifer.php",
"chars": 149,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Annotation;\n\nuse Attribute;\nuse Ray\\Di\\Di\\Qualifier;\n\n#[Attribute]\nfin"
},
{
"path": "tests/di/Fake/Annotation/FakeQualifierOnly.php",
"chars": 257,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Annotation;\n\nuse Attribute;\nuse Ray\\Di\\Di\\Qualifier;\n\n/**\n * Qualifier"
},
{
"path": "tests/di/Fake/Annotation/FakeRight.php",
"chars": 154,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di\\Annotation;\n\nuse Attribute;\nuse Ray\\Di\\Di\\Qualifier;\n\n#[Attribute, Qua"
},
{
"path": "tests/di/Fake/FakeAbstractClass.php",
"chars": 89,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nabstract class FakeAbstractClass\n{\n}\n"
},
{
"path": "tests/di/Fake/FakeAbstractDb.php",
"chars": 172,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nclass FakeAbstractDb\n{\n public $dbId;\n\n public function __cons"
},
{
"path": "tests/di/Fake/FakeAnnoClass.php",
"chars": 161,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Attribute;\n\n#[Attribute(Attribute::TARGET_CLASS)]\nclass FakeAnno"
},
{
"path": "tests/di/Fake/FakeAnnoInterceptor1.php",
"chars": 330,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\MethodInterceptor;\nuse Ray\\Aop\\MethodInvocation;\n\nclass "
},
{
"path": "tests/di/Fake/FakeAnnoInterceptor2.php",
"chars": 330,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\MethodInterceptor;\nuse Ray\\Aop\\MethodInvocation;\n\nclass "
},
{
"path": "tests/di/Fake/FakeAnnoInterceptor3.php",
"chars": 330,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\MethodInterceptor;\nuse Ray\\Aop\\MethodInvocation;\n\nclass "
},
{
"path": "tests/di/Fake/FakeAnnoInterceptor4.php",
"chars": 330,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\MethodInterceptor;\nuse Ray\\Aop\\MethodInvocation;\n\nclass "
},
{
"path": "tests/di/Fake/FakeAnnoInterceptor5.php",
"chars": 330,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\MethodInterceptor;\nuse Ray\\Aop\\MethodInvocation;\n\nclass "
},
{
"path": "tests/di/Fake/FakeAnnoInterceptorInterface.php",
"chars": 183,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\MethodInterceptor;\nuse Ray\\Aop\\MethodInvocation;\n\ninterf"
},
{
"path": "tests/di/Fake/FakeAnnoMethod1.php",
"chars": 133,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Attribute;\n\n#[Attribute(Attribute::TARGET_METHOD)]\nclass FakeAnn"
},
{
"path": "tests/di/Fake/FakeAnnoMethod2.php",
"chars": 133,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Attribute;\n\n#[Attribute(Attribute::TARGET_METHOD)]\nclass FakeAnn"
},
{
"path": "tests/di/Fake/FakeAnnoMethod3.php",
"chars": 133,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Attribute;\n\n#[Attribute(Attribute::TARGET_METHOD)]\nclass FakeAnn"
},
{
"path": "tests/di/Fake/FakeAnnoModule.php",
"chars": 1086,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nclass FakeAnnoModule extends AbstractModule\n{\n protected function"
},
{
"path": "tests/di/Fake/FakeAnnoOrderClass.php",
"chars": 205,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\n#[FakeAnnoClass]\nclass FakeAnnoOrderClass\n{\n #[FakeAnnoMethod1]\n "
},
{
"path": "tests/di/Fake/FakeAop.php",
"chars": 164,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nclass FakeAop implements FakeAopInterface\n{\n public function retu"
},
{
"path": "tests/di/Fake/FakeAopDoublyInstallModule.php",
"chars": 325,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nclass FakeAopDoublyInstallModule extends AbstractModule\n{\n protec"
},
{
"path": "tests/di/Fake/FakeAopGrapher.php",
"chars": 259,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nclass FakeAopGrapher implements FakeAopInterface\n{\n public $a;\n\n "
},
{
"path": "tests/di/Fake/FakeAopGrapherModule.php",
"chars": 382,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nclass FakeAopGrapherModule extends AbstractModule\n{\n protected fu"
},
{
"path": "tests/di/Fake/FakeAopInstallModule.php",
"chars": 263,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nclass FakeAopInstallModule extends AbstractModule\n{\n protected fu"
},
{
"path": "tests/di/Fake/FakeAopInterceptorModule.php",
"chars": 313,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nclass FakeAopInterceptorModule extends AbstractModule\n{\n protecte"
},
{
"path": "tests/di/Fake/FakeAopInterface.php",
"chars": 119,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\ninterface FakeAopInterface\n{\n public function returnSame($a);\n}\n"
},
{
"path": "tests/di/Fake/FakeAopInterfaceModule.php",
"chars": 221,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nclass FakeAopInterfaceModule extends AbstractModule\n{\n protected "
},
{
"path": "tests/di/Fake/FakeAopModule.php",
"chars": 368,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nclass FakeAopModule extends AbstractModule\n{\n protected function "
},
{
"path": "tests/di/Fake/FakeAssistedConsumer.php",
"chars": 758,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Di\\Di\\Assisted;\nuse Ray\\Di\\Di\\Named;\n\nclass FakeAssistedCons"
},
{
"path": "tests/di/Fake/FakeAssistedDb.php",
"chars": 118,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nclass FakeAssistedDb extends FakeAbstractDb\n{\n public $dbId;\n}\n"
},
{
"path": "tests/di/Fake/FakeAssistedDbModule.php",
"chars": 240,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nclass FakeAssistedDbModule extends AbstractModule\n{\n protected fu"
},
{
"path": "tests/di/Fake/FakeAssistedDbProvider.php",
"chars": 533,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nclass FakeAssistedDbProvider implements ProviderInterface\n{\n /** "
},
{
"path": "tests/di/Fake/FakeAssistedInjectConsumer.php",
"chars": 901,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Di\\Annotation\\FakeInjectOne;\nuse Ray\\Di\\Di\\Assisted;\nuse Ray"
},
{
"path": "tests/di/Fake/FakeAssistedInjectDb.php",
"chars": 299,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Di\\Di\\Assisted;\nuse Ray\\Di\\Di\\Inject;\n\nclass FakeAssistedInj"
},
{
"path": "tests/di/Fake/FakeAssistedParamsConsumer.php",
"chars": 285,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Di\\Di\\Assisted;\n\nclass FakeAssistedParamsConsumer\n{\n /**\n"
},
{
"path": "tests/di/Fake/FakeBcConstructorQualifierClass.php",
"chars": 386,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Di\\Annotation\\FakeQualifierOnly;\n\nclass FakeBcConstructorQua"
},
{
"path": "tests/di/Fake/FakeBcParameterQualifierClass.php",
"chars": 2008,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Di\\Annotation\\FakeInjectOne;\nuse Ray\\Di\\Di\\Inject;\n\nclass Fa"
},
{
"path": "tests/di/Fake/FakeBcParameterQualifierModule.php",
"chars": 400,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Di\\Annotation\\FakeInjectOne;\n\nclass FakeBcParameterQualifier"
},
{
"path": "tests/di/Fake/FakeBuiltin.php",
"chars": 207,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nclass FakeBuiltin\n{\n public $injector;\n\n public function __con"
},
{
"path": "tests/di/Fake/FakeCar.php",
"chars": 1992,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Di\\Di\\Inject;\nuse Ray\\Di\\Di\\Named;\nuse Ray\\Di\\Di\\PostConstru"
},
{
"path": "tests/di/Fake/FakeCarEngine.php",
"chars": 95,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nclass FakeCarEngine extends FakeEngine\n{\n}\n"
},
{
"path": "tests/di/Fake/FakeCarEngineModule.php",
"chars": 218,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nclass FakeCarEngineModule extends AbstractModule\n{\n protected fun"
},
{
"path": "tests/di/Fake/FakeCarInterface.php",
"chars": 83,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\ninterface FakeCarInterface\n{\n}\n"
},
{
"path": "tests/di/Fake/FakeCarModule.php",
"chars": 1232,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Aop\\NullInterceptor;\n\nclass FakeCarModule extends AbstractMo"
},
{
"path": "tests/di/Fake/FakeClassInstanceBindModule.php",
"chars": 367,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nclass FakeClassInstanceBindModule extends AbstractModule\n{\n priva"
},
{
"path": "tests/di/Fake/FakeClassWithBcParameterQualifier.php",
"chars": 463,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Ray\\Di\\Annotation\\FakeInjectOne;\n\nclass FakeClassWithBcParameter"
},
{
"path": "tests/di/Fake/FakeConcreteClass.php",
"chars": 173,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nclass FakeConcreteClass\n{\n public function __construct(FakeAbstra"
},
{
"path": "tests/di/Fake/FakeConstant.php",
"chars": 306,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Ray\\Di;\n\nuse Attribute;\nuse Ray\\Di\\Di\\Qualifier;\n\n#[Attribute(Attribute::TARG"
}
]
// ... and 111 more files (download for full content)
About this extraction
This page contains the full source code of the ray-di/Ray.Di GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 311 files (279.0 KB), approximately 77.0k tokens, and a symbol index with 940 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.