Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/demo-php8.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
Expand All @@ -22,10 +22,10 @@ jobs:

- name: Get composer cache directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT

- name: Cache dependencies
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
Expand All @@ -35,4 +35,4 @@ jobs:
run: composer install --no-interaction --no-progress --prefer-dist

- name: Run Demo
run: php demo-php8/run.php
run: php demo/run.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
run:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: FantasticFiasco/action-update-license-year@v2
Expand Down
87 changes: 87 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# 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
9 changes: 3 additions & 6 deletions demo/01a-linked-binding.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,9 @@ interface MovieListerInterface

class MovieLister implements MovieListerInterface
{
public $finder;

public function __construct(FinderInterface $finder)
{
$this->finder = $finder;
}
public function __construct(
public FinderInterface $finder
){}
}

class FinderModule extends AbstractModule
Expand Down
6 changes: 2 additions & 4 deletions demo/01b-linked-binding-setter-injection.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,9 @@ interface MovieListerInterface

class MovieLister implements MovieListerInterface
{
public $finder;
public FinderInterface $finder;

/**
* @Inject
*/
#[Inject]
public function setFinder(FinderInterface $finder)
{
$this->finder = $finder;
Expand Down
9 changes: 3 additions & 6 deletions demo/02-provider-binding.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,9 @@ interface MovieListerInterface

class MovieLister implements MovieListerInterface
{
/** @var Finder */
public $finder;

public function __construct(FinderInterface $finder)
{
$this->finder = $finder;
public function __construct(
public FinderInterface $finder
){
}
}

Expand Down
17 changes: 3 additions & 14 deletions demo/02a-named-by-qualifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,21 @@ class LegacyFinder implements FinderInterface
{
}

class ModernFinder implements FinderInterface
{
}

interface MovieListerInterface
{
}

class MovieLister implements MovieListerInterface
{
public $finder;
public FinderInterface $finder;

/**
* @Legacy
*/
public function __construct(FinderInterface $finder)
public function __construct(#[Legacy] FinderInterface $finder)
{
$this->finder = $finder;
}
}

/**
* @Annotation
* @Target("METHOD")
* @Qualifier
*/
#[Attribute(Attribute::TARGET_PARAMETER), Qualifier]
class Legacy
{
}
Expand Down
12 changes: 3 additions & 9 deletions demo/02b-named-by-named.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,9 @@ interface MovieListerInterface

class MovieLister implements MovieListerInterface
{
public $finder;

/**
* @Named("legacy")
*/
public function __construct(FinderInterface $finder)
{
$this->finder = $finder;
}
public function __construct(
#[Named('legacy')] public FinderInterface $finder
){}
}

class FinderModule extends AbstractModule
Expand Down
19 changes: 8 additions & 11 deletions demo/03-injection-point.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,22 @@ interface MovieListerInterface

class Finder implements FinderInterface
{
private $className;
private string $className;

public function __construct($className)
public function __construct(string $className)
{
$this->className = $className;
}

public function find()
public function find(): string
{
return sprintf('search for [%s]', $this->className);
}
}

class MovieLister implements MovieListerInterface
{
/** @var Finder */
public $finder;
public FinderInterface $finder;

public function __construct(FinderInterface $finder)
{
Expand All @@ -45,12 +44,10 @@ public function __construct(FinderInterface $finder)

class FinderProvider implements ProviderInterface
{
private $ip;

public function __construct(InjectionPointInterface $ip)
{
$this->ip = $ip;
}
public function __construct(
public InjectionPointInterface $ip
)
{}

/**
* {@inheritdoc}
Expand Down
2 changes: 1 addition & 1 deletion demo/05b-constructor-binding-setter-injection.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class Finder implements FinderInterface

class MovieLister implements MovieListerInterface
{
public $finder;
public FinderInterface $finder;

/**
* Setter Injection with no Inject annotation
Expand Down
4 changes: 1 addition & 3 deletions demo/finder/Db.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ public function __construct($dsn, $username, $password)
{
}

/**
* @PostConstruct
*/
#[PostConstruct]
public function init()
{
}
Expand Down
8 changes: 2 additions & 6 deletions demo/finder/DbFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,12 @@ public function __construct(DbInterface $db)
{
}

/**
* @Inject
*/
#[Inject]
public function setDb(DbInterface $db)
{
}

/**
* @Inject
*/
#[Inject]
public function setSorter(Sorter $sorter, Sorter $sorte2)
{
}
Expand Down
6 changes: 2 additions & 4 deletions demo/finder/MovieFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
declare(strict_types=1);

use Ray\Di\Di\Assisted;
use Ray\Di\Di\Inject;

class MovieFinder
{
/**
* @Assisted({"finder"})
*/
public function find($name, ?FinderInterface $finder = null)
public function find($name, #[Inject] ?FinderInterface $finder = null)
{
return sprintf('searching [%s] by [%s]', $name, get_class($finder));
}
Expand Down
2 changes: 1 addition & 1 deletion demo/finder/MovieLister.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public function __construct(FinderInterface $finder)
{
}

/** @Inject */
#[Inject]
public function setFinder01(FinderInterface $finder, FinderInterface $finder1, FinderInterface $finder2)
{
}
Expand Down
2 changes: 2 additions & 0 deletions demo/run.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

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');
Expand Down
3 changes: 3 additions & 0 deletions demo/tmp/-Ray_Di_Annotation_ScriptDir.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?php

return '/Users/akihito/git/Ray.Di/demo/tmp';
3 changes: 3 additions & 0 deletions demo/tmp/-dsn.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?php

return 'msql:host=localhost;dbname=test';
3 changes: 3 additions & 0 deletions demo/tmp/-password.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?php

return '';
3 changes: 3 additions & 0 deletions demo/tmp/-username.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?php

return 'root';
1 change: 1 addition & 0 deletions demo/tmp/03/03419867.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php return 'a:0:{}';
1 change: 1 addition & 0 deletions demo/tmp/04/0424916e.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php return 'a:0:{}';
1 change: 1 addition & 0 deletions demo/tmp/05/05cacb22.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php return 'a:0:{}';
1 change: 1 addition & 0 deletions demo/tmp/06/063abd7e.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php return 'a:0:{}';
1 change: 1 addition & 0 deletions demo/tmp/09/09a2a810.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php return 'a:0:{}';
1 change: 1 addition & 0 deletions demo/tmp/0a/0aac2e56.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php return 'a:0:{}';
1 change: 1 addition & 0 deletions demo/tmp/0f/0f4883c8.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php return 'a:0:{}';
1 change: 1 addition & 0 deletions demo/tmp/11/118d374f.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php return 'a:0:{}';
1 change: 1 addition & 0 deletions demo/tmp/16/16db7ca3.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php return 'a:0:{}';
1 change: 1 addition & 0 deletions demo/tmp/18/181572f3.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php return 'a:0:{}';
1 change: 1 addition & 0 deletions demo/tmp/1a/1a87dd68.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php return 'a:0:{}';
1 change: 1 addition & 0 deletions demo/tmp/1c/1c2a6b4f.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php return 'a:2:{i:0;O:63:"Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor":0:{}i:1;O:9:"Attribute":1:{s:5:"flags";i:36;}}';
1 change: 1 addition & 0 deletions demo/tmp/1d/1d519d44.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php return 'a:0:{}';
Loading
Loading