acc-check-dependency-injection

📁 dykyi-roman/awesome-claude-code 📅 2 days ago
1
总安装量
1
周安装量
#46293
全站排名
安装命令
npx skills add https://github.com/dykyi-roman/awesome-claude-code --skill acc-check-dependency-injection

Agent 安装分布

opencode 1
claude-code 1

Skill 文档

Dependency Injection Check

Analyze PHP code for proper dependency injection patterns.

Detection Patterns

1. New Keyword in Business Logic

// BAD: Hard-coded dependency
class OrderService
{
    public function process(Order $order): void
    {
        $mailer = new Mailer(); // Can't mock this
        $mailer->send($order->getCustomer(), 'confirmation');
    }
}

// GOOD: Injected dependency
class OrderService
{
    public function __construct(
        private MailerInterface $mailer,
    ) {}

    public function process(Order $order): void
    {
        $this->mailer->send($order->getCustomer(), 'confirmation');
    }
}

2. Service Locator Antipattern

// BAD: Service locator
class UserService
{
    public function register(UserData $data): User
    {
        $hasher = Container::get(PasswordHasher::class);
        $repository = Container::get(UserRepository::class);
        $mailer = Container::get(Mailer::class);

        // Dependencies are hidden
    }
}

// GOOD: Constructor injection
class UserService
{
    public function __construct(
        private PasswordHasher $hasher,
        private UserRepository $repository,
        private Mailer $mailer,
    ) {}

    // Dependencies are explicit
}

3. Static Method Calls

// BAD: Static calls can't be mocked
class ReportGenerator
{
    public function generate(): Report
    {
        $data = Database::query('SELECT ...');  // Static
        $date = Carbon::now();                   // Static
        $id = Uuid::uuid4();                     // Static

        return new Report($data, $date, $id);
    }
}

// GOOD: Injectable services
class ReportGenerator
{
    public function __construct(
        private Connection $database,
        private ClockInterface $clock,
        private UuidGenerator $uuidGenerator,
    ) {}

    public function generate(): Report
    {
        $data = $this->database->query('SELECT ...');
        $date = $this->clock->now();
        $id = $this->uuidGenerator->generate();

        return new Report($data, $date, $id);
    }
}

4. Missing Interface

// BAD: Concrete class dependency
class PaymentProcessor
{
    public function __construct(
        private StripeGateway $gateway, // Concrete class
    ) {}
}

// GOOD: Interface dependency
class PaymentProcessor
{
    public function __construct(
        private PaymentGatewayInterface $gateway, // Interface
    ) {}
}

5. Hidden Dependencies

// BAD: Uses global/superglobal
class UserController
{
    public function current(): User
    {
        $userId = $_SESSION['user_id']; // Hidden dependency
        return $this->repository->find($userId);
    }
}

// GOOD: Explicit dependency
class UserController
{
    public function __construct(
        private SessionInterface $session,
        private UserRepository $repository,
    ) {}

    public function current(): User
    {
        $userId = $this->session->get('user_id');
        return $this->repository->find($userId);
    }
}

6. Setter Injection Issues

// BAD: Optional setter injection
class OrderService
{
    private ?Logger $logger = null;

    public function setLogger(Logger $logger): void
    {
        $this->logger = $logger;
    }

    public function process(): void
    {
        $this->logger?->info('Processing'); // May be null
    }
}

// GOOD: Constructor injection
class OrderService
{
    public function __construct(
        private LoggerInterface $logger,
    ) {}

    public function process(): void
    {
        $this->logger->info('Processing');
    }
}

7. Factory Inside Class

// BAD: Factory logic in service
class NotificationService
{
    public function send(string $type, string $message): void
    {
        $channel = match($type) {
            'email' => new EmailChannel(),
            'sms' => new SmsChannel(),
            'push' => new PushChannel(),
        };
        $channel->send($message);
    }
}

// GOOD: Inject factory
class NotificationService
{
    public function __construct(
        private ChannelFactory $channelFactory,
    ) {}

    public function send(string $type, string $message): void
    {
        $channel = $this->channelFactory->create($type);
        $channel->send($message);
    }
}

8. Environment/Config Access

// BAD: Direct environment access
class ApiClient
{
    public function request(): Response
    {
        $key = getenv('API_KEY'); // Hidden dependency
        // ...
    }
}

// GOOD: Config injection
class ApiClient
{
    public function __construct(
        private string $apiKey, // Or ApiConfig object
    ) {}
}

Grep Patterns

# New keyword in methods
Grep: "new\s+[A-Z]\w+\(" --glob "**/*.php"

# Service locator
Grep: "Container::(get|make)|App::(make|resolve)" --glob "**/*.php"

# Static method calls
Grep: "[A-Z]\w+::\w+\(" --glob "**/*.php"

# Superglobals
Grep: "\$_(GET|POST|SESSION|COOKIE|ENV|SERVER)" --glob "**/*.php"

# getenv/putenv
Grep: "(getenv|putenv)\(" --glob "**/*.php"

Acceptable Uses of New

// OK: Value objects and DTOs
new Money(100, 'USD');
new DateTime('now');
new OrderId($uuid);

// OK: Exceptions
throw new InvalidArgumentException();

// OK: In factories (that's their job)
class UserFactory {
    public function create(): User {
        return new User();
    }
}

Severity Classification

Pattern Severity
Service locator 🟠 Major
New keyword for services 🟠 Major
Static method calls 🟠 Major
Superglobal access 🟠 Major
Missing interface 🟡 Minor
Setter injection 🟡 Minor

Output Format

### DI Issue: [Description]

**Severity:** 🟠/🟡
**Location:** `file.php:line`
**Type:** [Service Locator|New Keyword|Static Call|...]

**Issue:**
[Description of the DI problem]

**Current:**
```php
$mailer = new Mailer();

Suggested:

public function __construct(
    private MailerInterface $mailer,
) {}

Testing Impact: Cannot mock Mailer in unit tests. With injection, tests can use MockMailer.