AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MPL-2.0 Self-run

Dependency Injection

skill-garrettw-php-arch-skills-dependency-injection · by garrettw

Use this skill when wiring dependencies, configuring a DI container, designing plugin/extension points, or migrating away from legacy service locators in PHP. Triggers on questions about constructor injection, interface registration, swapping implementations, or testing without booting the container.

No reviews yet
0 installs
8 views
0.0% view→install

Install

$ agentstack add skill-garrettw-php-arch-skills-dependency-injection

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-garrettw-php-arch-skills-dependency-injection)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
23d ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Dependency Injection? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Dependency Injection Best Practices for PHP

When to Use a DI Container (and When NOT to)

A DI container is an infrastructure concern. Use it for applications that need flexible wiring, interface swapping, or framework integration. Libraries should use constructor injection directly and let the consumer resolve dependencies.

| Use a DI Container For | Do Not Use a Container For | |---------------------------------------------------|------------------------------------------| | Applications with many interchangeable services | Libraries and packages | | Need to swap implementations (test vs production) | Simple scripts with one or two classes | | Framework integration (Symfony, Laravel) | Throwaway code or prototypes |

The container should wire the application together at the edge, while the core remains ignorant of the container. This skill provides the rules for registering dependencies, migrating legacy locators, and injecting objects.

A [Plugin](references/plugin.md) is the purpose this wiring serves: define extension points (Ports) so new behavior is added by plugging in implementations (Adapters) at the composition root, without modifying the core. A plugin must extend the existing abstractions, never bypass them. It protects the framework / extension boundary — one of a family of boundary-protection patterns (with Gateway, Mapper, Remote Facade, DTO, and Special Case) that form the foundation of Hexagonal architecture; see [boundary-protection-patterns.md](../distribution-patterns/references/boundary-protection-patterns.md).

Numbered Workflows

1. Registering Dependencies

If deciding whether to create an interface and register it in the DI container:

  1. Check for Multiple Implementations. Are there multiple implementations (e.g., StripeAdapter and PayPalAdapter)?
  2. Check for Boundary Inversion. Is the application defining a port that the infrastructure implements?
  3. Check for Decorators. Do you need to wrap the class with caching or logging?
  4. If Yes to any: Create an interface and register the binding in the container configuration.
  5. If No to all: Depend on the concrete class directly and let the container autowire it. Do not blindly create interfaces for every class.

2. Testing with Constructor Injection

If writing tests for classes that use constructor injection:

  1. For Domain/Handler Tests: Construct the object using new. Pass in test doubles (mocks or fakes) for any infrastructure dependencies. Do not boot the DI container.
  2. For Integration/Feature Tests: Ask the test framework to resolve the controller or handler from the DI container.

3. Migrating Legacy Code

If modifying a legacy class that uses a service locator (Container::getInstance()->get()):

  1. Follow the Migration Sequence. Read the [Migration Sequence for Legacy Containers](references/migration-sequence.md).
  2. Extract to Constructor. Find every internal getInstance() call and add those dependencies as typed constructor properties.
  3. Fix Callers. Update all instantiations of the legacy class to pass the dependencies.
  4. Use Shims if Necessary. If the class is instantiated in 50 places you cannot change, use the temporary shim pattern to bridge the gap.

Boundaries

Always Do

  • Always use constructor injection for services, handlers, repositories, adapters, and listeners.
  • Always keep the container wiring logic at the framework edge (composition roots, service providers).
  • Always keep the domain core free of framework dependencies. It should resolve from tests or a composition root with no framework boot.
  • Always treat a plugin as a first-class architectural citizen: it implements a defined Port and obeys the same dependency rule and invariants as core code (see [plugin.md](references/plugin.md)).

Ask First

  • Ask before introducing a legacy shim if it is feasible to simply update all callers instead.

Never Do

  • Never use service locators inside domain objects, application handlers, or policies. They hide dependencies and couple core code to the framework.
  • Never let a plugin become a backdoor: it must not reach into core internals, write to the database directly, or skip domain invariants. Plug in via the defined Port only.

Related Patterns

  • The Factory pattern (variant selection, composition-root wiring, Singleton as anti-pattern) is covered in [creation-patterns.md](references/creation-patterns.md).

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.