Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Polycast Laravel Package

theodorejb/polycast

theodorejb/polycast brings type-safe casting to PHP: a simple Cast class converts values to int, float, bool, string, array, or DateTime, throwing clear exceptions when a value can't be cast instead of silently coercing it.

Deep Wiki
Context7

Getting Started

composer require theodorejb/polycast

Polycast is a tiny, framework-agnostic utility: no service provider, no config file, no facade. It ships a small set of cast helpers (namespaced functions or static methods — check src/ and the README for the exact entry points) that convert mixed values to int, float, or string and throw when the conversion would be lossy or ambiguous, instead of silently coercing the way PHP's native casts do.

Where to look first, in order:

  1. README — the public API surface and the three supported target types.
  2. src/ — the actual casting rules. This is where the contract lives.
  3. tests/ — the real specification. Read the edge-case cases ("12abc", " 42 ", "1e3", 1.0, true, null) before you rely on it anywhere.

First use case: sanitize untrusted input once, at the boundary, and let failures throw rather than becoming 0 or "".

use function TheodoreBrown\Polycast\to_int;

// Native: (int) "abc" === 0, silently. Polycast throws instead.
$page = to_int($request->query('page') ?? 1);

Implementation Patterns

Cast at the edge, not in the model. The package's value is that failures are loud. Call it in controllers, request/DTO factories, or console command handlers — places where you can convert an exception into a 422 or a clear CLI error. Once a value is a typed int/float/string, keep it typed; don't re-cast deeper in the stack.

DTO / value-object constructors are the strongest fit:

final class Pagination
{
    public function __construct(public readonly int $page, public readonly int $perPage)
    {
        // page/perPage already validated by the caller
    }

    public static function fromArray(array $input): self
    {
        return new self(
            to_int($input['page'] ?? 1),
            to_int($input['per_page'] ?? 25),
        );
    }
}

Database and CSV rows. PDO returns strings for INT/DECIMAL columns depending on driver and ATTR_STRINGIFY_FETCHES; CSV/JSON imports are all strings. Use Polycast at the mapping layer so the rest of the app sees real types.

Config and env parsing. env('FEATURE_LIMIT') / getenv() are strings or false. Wrap them in a small typed config object rather than sprinkling (int) around.

Map the exception to your validation layer. Catch the package's cast exception and rethrow as your domain/validation exception so HTTP and API layers stay framework-shaped:

try {
    $amount = to_float($input['amount']);
} catch (CastException $e) {
    throw ValidationException::withMessages(['amount' => 'Must be a number.']);
}

Compose, don't replace, validation. filter_var(..., FILTER_VALIDATE_INT) returns false and loses the distinction between "invalid" and "actually false". Polycast's throwing contract is easier to reason about; use it as the single conversion step and keep business rules (ranges, min/max) separate.

Static analysis. The strict return types make PHPStan/Psalm happy and eliminate a whole class of mixed-propagation warnings; annotate your DTO properties accordingly and let the analyzer enforce that casts happen before use.

Testing. Assert on behavior, not implementation: valid inputs return the expected native type, invalid inputs throw. The package's own tests are a good template.

Gotchas and Tips

  • Know the exact semantics before trusting it. The differentiator vs (int) is which strings are accepted. Confirm in tests/ how it handles "12abc", "0x1A", " 42 ", "042", "1e3", "+5", and "". Behavior you assume instead of verify is the #1 source of surprises in a 50-star utility.
  • Float→int is the classic trap. Native (int) 5.9 === 5 truncates. Expect Polycast to reject non-integral floats; if your code legitimately needs rounding, do it explicitly (to_int(round($x))) so the intent is visible.
  • Int overflow. Values above PHP_INT_MAX become floats in PHP. Decide up front whether huge numeric strings should throw or be rejected by a range check, and don't rely on the cast to catch it for you.
  • String→float is locale-independent. Good news: it parses . decimals regardless of setlocale. Bad news: your users may send "1,50"; handle that normalization before calling Polycast, not inside a catch.
  • Not everything is covered. The package handles int/float/string only. Booleans, dates, and enums are your responsibility — don't force a boolean through to_string() and expect "true".
  • null handling. Decide whether null throws or is defaulted at the call site (to_int($x ?? 0)). Prefer the explicit default; it documents intent and keeps the exception for genuinely bad data.
  • Composer autoload. If the helpers are namespaced functions, they're loaded via Composer's files autoload, not classmap. After adding the dependency run composer dump-autoload; in long-running workers (Octane, Swoole) restart the worker so the new files entry is picked up.
  • Don't cast twice. Converting to string and back to int re-introduces exactly the ambiguity the package exists to remove.
  • Debugging failures. When a cast throws in production, log the original value and its gettype() — " " vs "" vs null are easy to confuse in a stack trace.
  • Extension point is composition, not inheritance. Wrap Polycast in your own CastsInput helper (or a Cast value object) if you need project-wide defaults, custom messages, or metrics; the library is too small to warrant forking.
  • Performance is a non-issue relative to request handling; don't reach for native casts "for speed" in hot loops unless profiling actually says so — a silent corruption bug costs far more than a function call.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource