← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

Service Locator Anti-Pattern

Architecture Intermediate
debt(d5/e5/b6/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches' (d5) — phpstan/deptrac/semgrep rules can flag app()->make() or Container calls inside domain code, but this requires custom rules and architectural boundaries configuration, not default linting.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5) — quick_fix says replace with constructor injection, but doing so cascades: callers must now provide the dependency, requiring changes to factories, bindings, and tests across the component.

b6 Burden Structural debt — long-term weight of choosing wrong

Closest to 'strong gravitational pull' (b7) minus one (b6) — applies_to spans web/cli/queue-worker so reach is wide; once domain classes lean on the locator, every new feature follows the same hidden-dependency shape, but it's not quite system-defining since it can be peeled back class-by-class.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7) — the misconception explicitly states devs equate service locator with DI; it contradicts how DI is supposed to work (explicit signature) by hiding deps in implementation, fooling competent developers who think they're 'doing DI' via app().

About DEBT scoring →

Also Known As

service locator registry pattern global service registry

TL;DR

A class that fetches its own dependencies from a global registry — hiding them from the constructor signature and making dependencies implicit, untestable, and hard to trace.

Explanation

A service locator provides a static or global registry that classes query to obtain their dependencies. Unlike dependency injection (where dependencies are declared in the constructor), service locators make dependencies implicit — you cannot tell what a class needs without reading its implementation. This makes testing harder (must configure the global registry), increases coupling to the locator itself, and makes dependency graphs opaque. It is listed as an anti-pattern by most DI literature.

Common Misconception

Service locator and dependency injection are equivalent — DI makes dependencies explicit in the signature; service locator hides them in the implementation.

Why It Matters

A class using a service locator can have hidden dependencies that break tests, change between calls, and are impossible to discover without reading the implementation source.

Common Mistakes

  • Using Laravel's app() helper inside domain classes — decouples from HTTP but couples to the framework container.
  • Not distinguishing service locator (anti-pattern in domain code) from the DI container itself (legitimate infrastructure).
  • Passing the container into classes as a constructor argument — this is a service locator, not DI.
  • Testing classes that use service locators by configuring the global container — fragile, order-dependent tests.

Code Examples

✗ Vulnerable
// Service locator — hidden dependencies:
class OrderService {
    public function place(Order $order): void {
        // Dependencies hidden inside — impossible to see from the outside:
        $mailer = app(Mailer::class);
        $payment = app(PaymentGateway::class);
        $logger = app(Logger::class);
        // Test must configure global app() — hidden coupling
    }
}
✓ Fixed
// Dependency injection — explicit dependencies:
class OrderService {
    public function __construct(
        private readonly Mailer $mailer,
        private readonly PaymentGateway $payment,
        private readonly LoggerInterface $logger,
    ) {} // All dependencies visible in signature — trivial to test

    public function place(Order $order): void {
        // Uses injected dependencies
    }
}

Added 15 Mar 2026
Edited 22 Mar 2026
Views 114
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings S 0 pings M 1 ping T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 2 pings T 0 pings W 0 pings T 2 pings F 0 pings S 0 pings S 1 ping M 0 pings T 1 ping W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 1 ping T 1 ping W 1 ping T 1 ping F 0 pings S 1 ping S 0 pings M
No pings yet today
Sogou 1
Google 11 PetalBot 11 Amazonbot 10 ChatGPT 8 SEMrush 8 Ahrefs 7 Scrapy 3 Sogou 3 Bing 3 Perplexity 2 Unknown AI 2 Applebot 2 Meta AI 1 Twitter/X 1
crawler 66 crawler_json 6
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: High
⚡ Quick Fix
Replace app()->make() and Container::getInstance() inside business logic with constructor injection — the service locator hides dependencies making code hard to test and understand
📦 Applies To
any web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
app()->make() or resolve() inside service class; static Container::getInstance() in business logic; Facade usage in domain code
Auto-detectable: ✓ Yes phpstan deptrac semgrep
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Medium ✗ Manual fix Fix: High Context: Class Tests: Update


✓ schema.org compliant