PHPackages                             laikait/laika-relay - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. laikait/laika-relay

ActivePackage[Framework](/categories/framework)

laikait/laika-relay
===================

Laika PHP Framework Relay Service

v1.2.1(2w ago)03031MITPHP &gt;=8.1

Since Jun 21Compare

[ Source](https://github.com/laikait/laika-relay)[ Packagist](https://packagist.org/packages/laikait/laika-relay)[ RSS](/packages/laikait-laika-relay/feed)WikiDiscussions Synced 2w ago

READMEChangelog (10)DependenciesVersions (15)Used By (1)

Laika Framework Relay (Service Container &amp; Static Proxy)
============================================================

[](#laika-framework-relay-service-container--static-proxy)

**Relay** is the service container and static proxy system built for the [Laika Framework](https://github.com/laikait/laika-framework). It gives you a lightweight dependency injection container (`RelayRegistry`), a clean static proxy base (`Relay`), and a two-phase provider system (`RelayProvider` + `ProviderRegistry`) that lets third-party packages register their own services into the framework.

> Part of `laikait/laika-core` · Requires PHP 8.1+

---

Table of Contents
-----------------

[](#table-of-contents)

- [How It Works](#how-it-works)
- [File Structure](#file-structure)
- [RelayRegistry](#relayregistry)
    - [instance()](#instance)
    - [singleton()](#singleton)
    - [bind()](#bind)
    - [make()](#make)
    - [has()](#has)
    - [forgetInstance()](#forgetinstance)
    - [Lifetime Comparison](#lifetime-comparison)
- [Auto-Wiring](#auto-wiring)
- [RelayProvider](#RelayProvider)
    - [register()](#register)
    - [boot()](#boot)
    - [register() vs boot()](#register-vs-boot)
- [ProviderRegistry](#providerregistry)
- [Bootstrap](#bootstrap)
- [Third-Party Integration](#third-party-integration)
- [Relay — The Static Proxy](#relay--the-static-proxy)
    - [Creating a Relay Class](#creating-a-relay-class)
    - [Using a Relay](#using-a-relay)
    - [Method Chaining](#method-chaining)
    - [Switching Instances at Runtime](#switching-instances-at-runtime)
- [Testing](#testing)
- [Exceptions](#exceptions)

---

How It Works
------------

[](#how-it-works)

```
Your Code
    │
    ▼
Auth::check()                    ← Relay proxy  (static call)
    │
    ▼
RelayRegistry::make('auth')      ← Container    (resolves & caches)
    │
    ▼
Laika\Core\Auth\Auth::check()    ← Real class   (real method)

```

There are three independent pieces:

ClassRole`RelayRegistry`The container. Holds bindings, resolves and caches instances.`Relay`Abstract base. Forwards static calls to the resolved instance.`RelayProvider`Integration point. Packages extend this to register services.`ProviderRegistry`Manages provider lifecycle — calls `register()` then `boot()`.---

File Structure &amp; Default Services
-------------------------------------

[](#file-structure--default-services)

```
services/       # NAMESPACE: Laika\Service
└── Template/
    ├── Asset.php                       # HTML Template Asset Relay Class Container
    ├── Meta.php                        # HTML Template Meta Relay Class Container
└── Activity.php                        # Activity Relay Class Container
└── Api.php                             # Api Relay Class Container
└── ClientAuth.php                      # ClientAuth Relay Class Container
└── Config.php                          # Config Relay Class Container
└── Cookie.php                          # Cookie Relay Class Container
└── CSRF.php                            # CSRF Relay Class Container
└── Date.php                            # Date Relay Class Container
└── DB.php                              # DB Relay Class Container
└── Directory.php                       # Directory Relay Class Container
└── Email.php                           # Email Relay Class Container
└── File.php                            # File Relay Class Container
└── Hook.php                            # Hook Relay Class Container
└── Image.php                           # Image Relay Class Container
└── Infra.php                           # Infra Relay Class Container
└── IP.php                              # IP Relay Class Container
└── Local.php                           # Local Relay Class Container
└── Math.php                            # Math Relay Class Container
└── Meta.php                            # Meta Relay Class Container (Get Class Container Comments)
└── Nav.php                             # Nav Relay Class Container
└── Option.php                          # Option Relay Class Container
└── Page.php                            # Page Relay Class Container
└── Redirect.php                        # Redirect Relay Class Container
└── Regex.php                           # Regex Relay Class Container
└── Request.php                         # Request Relay Class Container
└── Response.php                        # Response Relay Class Container
└── StaffAuth.php                       # StaffAuth Relay Class Container
└── Token.php                           # Token Relay Class Container
└── Unique.php                          # Unique Relay Class Container
└── Upload.php                          # Upload Relay Class Container
└── Url.php                             # Url Relay Class Container
└── Vault.php                           # Vault Relay Class Container
└── Visitor.php                         # Visitor Relay Class Container

src/            # NAMESPACE: Laika\Relay
└── Exceptions/
    ├── RelayException.php              # Exception Class

└── Relay.php                           # Abstract base — extend to create a proxy
└── RelayRegistry.php                   # The container
└── RelayProvider.php                   # Relay Provider
└── ProviderRegistry.php                # Manages provider loading and booting
└── CoreProviders.php                    # Core Services Container

```

> `services/` \[`Laika\Service\*`\] is a convention, not a requirement. Relay classes can live anywhere.

---

RelayRegistry
-------------

[](#relayregistry)

The container. All services are registered here before the application starts handling requests.

```
use Laika\Relay\RelayRegistry;

$registry = new RelayRegistry();
```

---

### `instance()`

[](#instance)

Register an **already-constructed object** directly.

```
$registry->instance(string $key, object $instance): static
```

The registry stores exactly the object you give it — it never calls `new`. The object is available immediately on `make()`.

```
$pdo = new PDO($dsn, $user, $pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$registry->instance('db', $pdo);
```

Use when the object already exists before the registry is set up, or when construction has side effects that must be controlled manually.

---

### `singleton()`

[](#singleton)

Register a **singleton binding** — built once on the first `make()` call, then cached and reused for the lifetime of the request.

```
$registry->singleton(string $key, Closure|string $concrete, array $args = []): static
```

```
// Class string — no args needed
$registry->singleton('session', Session::class);

// Class string — with primitive args (positional)
$registry->singleton('mailer', Mailer::class, ['smtp']);

// Class string — with primitive args (named)
$registry->singleton('queue', DatabaseDriver::class, [
    'table'   => 'async_jobs',
    'retries' => 3,
]);

// Closure — manual control, receives the registry
$registry->singleton('db', function (RelayRegistry $r) {
    $config = $r->make('config');
    $pdo    = new PDO(
        $config->get('db.dsn'),
        $config->get('db.user'),
        $config->get('db.pass')
    );
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    return $pdo;
});

// Closure — conditional factory
$registry->singleton('cache', function (RelayRegistry $r) {
    return match ($r->make('config')->get('cache.driver')) {
        'redis' => new RedisCache(),
        'file'  => new FileCache(),
        default => new ArrayCache(),
    };
});
```

Use for stateful services shared across the entire request: session, auth, config, mailer, cache.

---

### `bind()`

[](#bind)

Register a **transient binding** — a brand-new instance is created on every `make()` call. Nothing is ever cached.

```
$registry->bind(string $key, Closure|string $concrete, array $args = []): static
```

```
$registry->bind('validator', Validator::class);

$v1 = $registry->make('validator');
$v2 = $registry->make('validator');
// $v1 !== $v2  — completely independent instances
```

Use for stateless, disposable objects where shared state would be a bug: validators, form request objects, DTOs, value objects.

---

### `make()`

[](#make)

Resolve a binding by key and return the object.

```
$auth = $registry->make('auth');
```

**Resolution order:**

```
1. Pre-bound instance      (instance())
2. Cached singleton        (already resolved on a prior make())
3. Singleton binding       → build, cache, return
4. Transient binding       → build fresh, return (no cache)
5. Bare class name         → attempt direct auto-wire if class exists
6. RelayException          → nothing matched

```

---

### `has()`

[](#has)

Check whether a key has any binding registered.

```
if ($registry->has('payment')) {
    $gateway = $registry->make('payment');
}
```

---

### `forgetInstance()`

[](#forgetinstance)

Clear a cached singleton instance, forcing re-resolution on the next `make()`.

```
$registry->forgetInstance('date');
$registry->singleton('date', Date::class, ['America/New_York']);

// Next make('date') builds a fresh instance with the new args
```

---

### Lifetime Comparison

[](#lifetime-comparison)

MethodWho builds itHow many instancesWhen builtCached`instance()`You1 (yours)Before registrationYes — immediately`singleton()`Registry1On first `make()`Yes — after first use`bind()`RegistryN (one per call)On every `make()`Never> **Prefer `singleton()` over `instance()`** for most services. `singleton()` is **lazy** — if nothing ever calls `make('x')`, the object is never constructed. `instance()` is **eager** — the object exists the moment you register it, whether anything uses it or not.

---

Auto-Wiring
-----------

[](#auto-wiring)

When a **class string** is registered (not a Closure), the registry uses PHP reflection to resolve constructor parameters automatically.

```
// Auth::__construct(Session $session, Config $config)
// Both 'session' and 'config' are already in the registry → auto-wired

$registry->singleton('session', Session::class);
$registry->singleton('config',  Config::class);
$registry->singleton('auth',    Auth::class);   // Session and Config injected automatically
```

**Per-parameter resolution order:**

```
1. Type-hinted class found in registry        → make() it
2. Type-hinted class not in registry, exists  → build() recursively
3. Primitive — named key in $args             → use it
4. Primitive — positional in $args            → use it
5. Has a default value                        → use it
6. Nullable                                   → pass null
7. Nothing matched                            → throw RelayException

```

**Mixed — auto-wire objects, supply primitives:**

```
// Mailer::__construct(Config $config, string $driver)
// Config is in the registry; 'smtp' cannot be auto-wired
$registry->singleton('mailer', Mailer::class, ['smtp']);
```

---

RelayProvider
-------------

[](#relayprovider)

The integration point for packages. Extend `RelayProvider` and implement `register()`. Optionally override `boot()`.

```
