PHPackages                             alexkart/typed-registry-laravel - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. alexkart/typed-registry-laravel

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

alexkart/typed-registry-laravel
===============================

Laravel integration for typed-registry with type-casting providers and facades

0.5.0(1mo ago)1321↓50%MITPHPPHP ^8.3CI passing

Since Oct 20Pushed 1mo agoCompare

[ Source](https://github.com/alexkart/typed-registry-laravel)[ Packagist](https://packagist.org/packages/alexkart/typed-registry-laravel)[ RSS](/packages/alexkart-typed-registry-laravel/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (5)Dependencies (14)Versions (6)Used By (0)

typed-registry-laravel
======================

[](#typed-registry-laravel)

Laravel integration for [typed-registry](https://github.com/alexkart/typed-registry) following Laravel best practices for environment variable and configuration access.

[![Tests](https://github.com/alexkart/typed-registry-laravel/actions/workflows/tests.yml/badge.svg)](https://github.com/alexkart/typed-registry-laravel/actions)[![PHPStan Level](https://camo.githubusercontent.com/c47b2ba3238269b2d6f0e8c346934f4e94ee7ff7345c2738e62830182711717f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6d61782d626c75652e737667)](https://phpstan.org/)[![License: MIT](https://camo.githubusercontent.com/784362b26e4b3546254f1893e778ba64616e362bd6ac791991d2c9e880a3a64e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d677265656e2e737667)](LICENSE)

Why?
----

[](#why)

Laravel's `env()` and `config()` helpers return `mixed` values, making strict type checking difficult. This package provides:

- **Type-safe config access** - `TypedConfig` facade and `typedConfig()` helper with strict return types
- **Type-safe env access** - `typedEnv()` helper for use in config files only (following Laravel best practices)
- **String-preserving env access** - `typedEnvString()` helper for values that must stay strings (passwords, tokens)
- **Intelligent casting** - Environment variables automatically cast from strings (`"8080"` → `8080`, `"1e3"` → `1000.0`)
- **PHPStan ready** - Works seamlessly with static analysis at max level
- **Zero runtime overhead** - Simple wrappers around Laravel's existing systems

Installation
------------

[](#installation)

```
composer require alexkart/typed-registry-laravel
```

Requires:

- PHP 8.3+
- Laravel 11+ or 12+ or 13+

The package uses Laravel's auto-discovery feature. The service provider and facade are registered automatically.

Quick Start
-----------

[](#quick-start)

### Environment Variables in Config Files

[](#environment-variables-in-config-files)

**Following Laravel Best Practices:** Environment variables should ONLY be accessed in config files, never directly in controllers or services.

```
// config/app.php
return [
    'name' => typedEnv()->getStringOr('APP_NAME', 'Laravel'),
    'debug' => typedEnv()->getBoolOr('APP_DEBUG', false),
    'port' => typedEnv()->getIntOr('APP_PORT', 8080),          // "8080" → 8080
    'timeout' => typedEnv()->getFloatOr('TIMEOUT', 2.5),       // "2.5" → 2.5
    'max_items' => typedEnv()->getInt('MAX_ITEMS'),            // Throws if missing
];
```

### Configuration Access Everywhere

[](#configuration-access-everywhere)

Use the `TypedConfig` facade or `typedConfig()` helper in controllers, services, and anywhere else:

```
use TypedRegistry\Laravel\Facades\TypedConfig;

class UserController
{
    public function index()
    {
        $perPage = TypedConfig::getInt('app.pagination.per_page');
        $appName = TypedConfig::getString('app.name');
        $features = TypedConfig::getStringList('app.enabled_features');

        // Or use the helper
        $timeout = typedConfig()->getFloat('app.timeout');
    }
}
```

Features
--------

[](#features)

### `typedEnv()` Helper - For Config Files Only

[](#typedenv-helper---for-config-files-only)

Wraps `Illuminate\Support\Env` with intelligent type casting for numeric strings:

```
// config/app.php
return [
    // Automatic type casting from .env strings:
    'port' => typedEnv()->getInt('PORT'),           // "8080" → int(8080)
    'rate' => typedEnv()->getFloat('RATE'),         // "2.5" → float(2.5)
    'limit' => typedEnv()->getFloat('LIMIT'),       // "1e3" → float(1000.0)
    'debug' => typedEnv()->getBool('APP_DEBUG'),    // "true" → bool(true)

    // With defaults (never throws):
    'name' => typedEnv()->getStringOr('APP_NAME', 'Laravel'),
    'timeout' => typedEnv()->getFloatOr('TIMEOUT', 30.0),
];
```

**Casting Rules:**

- Numeric strings → `int` or `float` based on format (handles scientific notation, leading zeros, whitespace, overflow)
- Boolean strings (`"true"`, `"false"`) → `bool` (handled by Laravel's `Env`)
- Null strings (`"null"`, `"(null)"`) → `null` (handled by Laravel's `Env`)
- All other strings remain unchanged

### `typedEnvString()` Helper - For String Values

[](#typedenvstring-helper---for-string-values)

Use this helper when you have environment variables that are semantically strings but may contain only digits (passwords, tokens, API keys):

```
// config/auth.php
return [
    // Problem: typedEnv() casts "123456" to int, getStringOr returns ''
    // 'password' => typedEnv()->getStringOr('API_PASSWORD', ''),

    // Solution: typedEnvString() keeps all values as strings
    'password' => typedEnvString()->getStringOr('API_PASSWORD', ''),
    'token' => typedEnvString()->getString('API_TOKEN'),
];
```

**Casting Rules:**

- All scalar values (string, int, float, bool) → `string`
- Booleans: `true` → `"1"`, `false` → `""` (PHP's native casting)
- Null remains `null`

### `TypedConfig` Facade - Use Anywhere

[](#typedconfig-facade---use-anywhere)

Wraps Laravel's `Config` facade with **strict typing, no casting**:

```
use TypedRegistry\Laravel\Facades\TypedConfig;

// In controllers, services, jobs, etc.
$driver = TypedConfig::getString('database.default');
$port = TypedConfig::getInt('database.connections.mysql.port');
$options = TypedConfig::getStringMap('database.connections.mysql.options');

// With defaults:
$perPage = TypedConfig::getIntOr('app.pagination.per_page', 15);
```

Or use the helper function:

```
$driver = typedConfig()->getString('database.default');
```

Full API
--------

[](#full-api)

All three helpers (`typedEnv()`, `typedEnvString()`, and `TypedConfig`) expose the same 20 methods from `TypedRegistry`:

### Primitive Getters

[](#primitive-getters)

```
->getString('KEY');   // string - throws if missing/wrong type
->getInt('KEY');      // int
->getBool('KEY');     // bool
->getFloat('KEY');    // float
```

### Nullable Variants

[](#nullable-variants)

```
->getNullableString('KEY');  // string|null
->getNullableInt('KEY');     // int|null
->getNullableBool('KEY');    // bool|null
->getNullableFloat('KEY');   // float|null
```

### With Defaults (Never Throws)

[](#with-defaults-never-throws)

```
->getStringOr('KEY', 'default');  // Returns default if missing/wrong type
->getIntOr('KEY', 8080);
->getBoolOr('KEY', false);
->getFloatOr('KEY', 1.5);
```

### Lists (Sequential Arrays)

[](#lists-sequential-arrays)

```
->getStringList('KEY');  // list
->getIntList('KEY');     // list
->getBoolList('KEY');    // list
->getFloatList('KEY');   // list
```

### Maps (Associative Arrays with String Keys)

[](#maps-associative-arrays-with-string-keys)

```
->getStringMap('KEY');  // array
->getIntMap('KEY');     // array
->getBoolMap('KEY');    // array
->getFloatMap('KEY');   // array
```

Type Casting Behavior
---------------------

[](#type-casting-behavior)

### EnvProvider - Intelligent Casting

[](#envprovider---intelligent-casting)

The `EnvProvider` (used by `typedEnv()`) intelligently casts numeric environment variable strings:

```
// Integer casting (handles edge cases)
"123"    → int(123)
"-456"   → int(-456)
"0"      → int(0)
"042"    → int(42)     // Leading zeros removed
"-042"   → int(-42)    // Negative with leading zeros
"+42"    → int(42)     // Leading plus removed
" 042 "  → int(42)     // Whitespace trimmed

// Integer overflow protection (values exceeding PHP_INT_MAX/MIN)
"9223372036854775808"  → float(9.223372036854776E+18)  // Too large for int
"-9223372036854775809" → float(-9.223372036854776E+18) // Too small for int

// Float casting (decimal point or scientific notation)
"3.14"   → float(3.14)
"0.0"    → float(0.0)
"1e3"    → float(1000.0)        // Scientific notation
"2.5e-4" → float(0.00025)       // Scientific with decimal
"1E10"   → float(10000000000.0) // Uppercase E
"042.5"  → float(42.5)

// No casting
"Laravel"  → "Laravel"  // Non-numeric
"123abc"   → "123abc"   // Mixed alphanumeric
""         → ""         // Empty string

// Laravel's Env handles these:
"true"     → bool(true)
"false"    → bool(false)
"null"     → null
"(null)"   → null
```

### EnvStringProvider - Cast to String

[](#envstringprovider---cast-to-string)

The `EnvStringProvider` (used by `typedEnvString()`) casts all scalar values to strings:

```
// All values become strings
"123456"   → "123456"   // Numeric string preserved
"3.14"     → "3.14"     // Float string preserved
"1e3"      → "1e3"      // Scientific notation preserved
"042"      → "042"      // Leading zeros preserved
"Laravel"  → "Laravel"  // Non-numeric unchanged

// Laravel's Env converts these first, then we cast to string:
"true"     → "1"        // bool(true) → string
"false"    → ""         // bool(false) → string
"null"     → null       // Stays null (not scalar)
```

### ConfigProvider - No Casting

[](#configprovider---no-casting)

ConfigProvider performs **zero type coercion**. Values must be stored with the correct type:

```
// config/app.php
return [
    'port' => 8080,        // ✅ int - TypedConfig::getInt() works
    'port_str' => '8080',  // ❌ string - TypedConfig::getInt() throws
];
```

Error Handling
--------------

[](#error-handling)

### Strict Getters Throw on Type Mismatch

[](#strict-getters-throw-on-type-mismatch)

```
use TypedRegistry\RegistryTypeError;

try {
    $port = TypedConfig::getInt('app.name'); // If 'app.name' is a string
} catch (RegistryTypeError $e) {
    // "[typed-registry] key 'app.name' must be int, got 'Laravel'"
}
```

### Default Getters Never Throw

[](#default-getters-never-throw)

```
// Returns default value on missing key OR type mismatch
$port = typedEnv()->getIntOr('NONEXISTENT_PORT', 8080);  // 8080
$timeout = TypedConfig::getFloatOr('cache.timeout', 3.0); // 3.0
```

Real-World Example
------------------

[](#real-world-example)

```
// config/app.php
return [
    'name' => typedEnv()->getStringOr('APP_NAME', 'Laravel'),
    'env' => typedEnv()->getStringOr('APP_ENV', 'production'),
    'debug' => typedEnv()->getBoolOr('APP_DEBUG', false),
    'url' => typedEnv()->getStringOr('APP_URL', 'http://localhost'),

    'timezone' => 'UTC',

    'locale' => typedEnv()->getStringOr('APP_LOCALE', 'en'),

    'providers' => [
        // Service providers...
    ],
];
```

```
// app/Http/Controllers/DashboardController.php
use TypedRegistry\Laravel\Facades\TypedConfig;

class DashboardController extends Controller
{
    public function index()
    {
        $appName = TypedConfig::getString('app.name');
        $isDebug = TypedConfig::getBool('app.debug');
        $locale = TypedConfig::getString('app.locale');

        return view('dashboard', compact('appName', 'isDebug', 'locale'));
    }
}
```

PHPStan Integration
-------------------

[](#phpstan-integration)

The package works seamlessly with PHPStan at max level:

```
/** @var int $port */
$port = TypedConfig::getInt('app.port'); // PHPStan knows this is int

/** @var list $hosts */
$hosts = TypedConfig::getStringList('app.hosts'); // PHPStan knows the shape
```

Development
-----------

[](#development)

```
# Install dependencies
composer install

# Run tests
composer test
# or: vendor/bin/phpunit

# Run static analysis
composer phpstan
# or: vendor/bin/phpstan analyse
```

**Quality Standards:**

- PHPStan Level: Max (10) with strict rules
- Test Coverage: All providers and facades
- PHP Version: 8.3+
- Laravel Version: 11+, 12+, 13+

Comparison with Core Package
----------------------------

[](#comparison-with-core-package)

Feature`alexkart/typed-registry``alexkart/typed-registry-laravel`FrameworkFramework-agnosticLaravel-specificType CastingNone (strict only)`EnvProvider` casts numeric stringsString PreservationN/A`EnvStringProvider` keeps all as stringsFacadesNo`TypedConfig`Helper FunctionsNo`typedEnv()`, `typedEnvString()`, `typedConfig()`Auto-discoveryN/AYesLaravel Best PracticesN/AEnforced (env only in config)Contributing
------------

[](#contributing)

Contributions are welcome! Please ensure:

1. All tests pass (`vendor/bin/phpunit`)
2. PHPStan Level 10 passes (`vendor/bin/phpstan analyse`)
3. Code follows existing style (strict types, final classes)

License
-------

[](#license)

MIT License. See [LICENSE](LICENSE) for details.

Credits
-------

[](#credits)

- Built on [alexkart/typed-registry](https://github.com/alexkart/typed-registry)
- Maintained by the TypedRegistry contributors

---

**Questions?** Open an issue on [GitHub](https://github.com/alexkart/typed-registry-laravel/issues).

###  Health Score

42

—

FairBetter than 90% of packages

Maintenance90

Actively maintained with recent releases

Popularity18

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity44

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~38 days

Total

5

Last Release

51d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/9946155ed284d2d4147cccc0c9e3fdeaf59310adf1145962d46f6a43820cb4c2?d=identicon)[alexkart](/maintainers/alexkart)

---

Top Contributors

[![alexkart](https://avatars.githubusercontent.com/u/8249105?v=4)](https://github.com/alexkart "alexkart (15 commits)")

---

Tags

PHPStanlaravelstatic analysisconfigenvstricttyped-registry

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/alexkart-typed-registry-laravel/health.svg)

```
[![Health](https://phpackages.com/badges/alexkart-typed-registry-laravel/health.svg)](https://phpackages.com/packages/alexkart-typed-registry-laravel)
```

###  Alternatives

[larastan/larastan

Larastan - Discover bugs in your code without running it. A phpstan/phpstan extension for Laravel

6.4k43.5M5.2k](/packages/larastan-larastan)[spatie/laravel-livewire-wizard

Build wizards using Livewire

4061.0M4](/packages/spatie-laravel-livewire-wizard)[bensampo/laravel-embed

Painless responsive embeds for videos, slideshows and more.

142146.8k](/packages/bensampo-laravel-embed)[dragon-code/pretty-routes

Pretty Routes for Laravel

10058.7k4](/packages/dragon-code-pretty-routes)[laracraft-tech/laravel-useful-additions

A collection of useful Laravel additions!

58109.4k](/packages/laracraft-tech-laravel-useful-additions)[watson/nameable

Format names of users into full, familiar and abbreviated forms

299.7k](/packages/watson-nameable)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
