pinkary-project/type-guard
A lightweight Pinkary package that brings expressive runtime type guards to PHP and Laravel apps, letting you assert and validate value types safely and fail fast with clear errors instead of scattered manual checks.
Architecture fit. pinkary-project/type-guard is a standalone, Composer-installable PHP utility with no framework coupling. It slots into a Laravel codebase as a leaf dependency — no service provider, no config, no facade required — and equally into plain PHP services. Its value proposition is narrow and complementary: it makes runtime type checks (is_string, is_array, instanceof, etc.) legible to static analysis so that PHPStan/Larastan can narrow a variable's type after a guard clause. That places it in the same layer as webmozart/assert and the type-narrowing features of spatie/laravel-data, not in the request-validation or DTO-transformation layer. For a Laravel shop that already treats PHPStan as a CI gate, the fit is good; for a shop without static analysis, the library delivers almost no value and should not be adopted.
Integration feasibility. Low effort. A single composer require --dev (or require if guards are used at runtime), no publishing of assets, no migration. Adoption can start in one module and fan out. The realistic integration surface is service classes, action classes, and console commands where untyped input (JSON payloads, mixed return types, config arrays) must be narrowed before use. The main effort is not installing the package — it is establishing or extending the PHPStan baseline so the narrowing pays off.
Technical risk. Runtime risk is near zero: the library is small, MIT-licensed, and executes trivial checks. The material risks are (a) adoption and maturity — 198 stars, an unlisted repository, and a composite score of 2.41 with an opportunity score of 1.9 signal a niche, low-signal package with limited independent validation; (b) single-maintainer/bus-factor exposure, typical of Pinkary-adjacent tooling; (c) coupled toolchain risk — the package's real deliverable is PHPStan stubs/extensions, so its usefulness is bound to specific PHPStan major versions and to whether Larastan resolves the stubs correctly. A PHPStan upgrade can silently degrade narrowing without any test failing.
Key questions. Which PHP minor versions and which PHPStan/Larastan majors are supported, and is that documented or inferred? Do guards return booleans (usable in if) or throw (usable as assertions), and can both modes coexist? Does it ship PHPStan stubs/extensions out of the box, and are they auto-loaded or opt-in via phpstan.neon? How does it behave at function and closure boundaries — does narrowing survive, or only apply locally? What is the maintainer's release cadence and issue-response history over the last twelve months? Is there a documented migration or comparison against assert() with @phpstan-assert annotations, which PHPStan supports natively and which would make this dependency optional?
Stack fit. Best fit is PHP 8.2+ on Laravel 10/11 with PHPStan (plus Larastan) already running in CI at a meaningful level (5+). It also fits non-Laravel PHP services. It does not fit teams without static analysis, and it is redundant where the codebase is already strongly typed end-to-end or already standardized on @phpstan-assert docblocks.
Migration path. Add as a dev dependency first, pin an exact version, and run it alongside existing code without changing behavior. Pilot in one bounded module — ideally the boundary where external input enters (HTTP payload handlers, queue job payloads, third-party API response parsers) — because that is where mixed is unavoidable and narrowing has the highest payoff. Backfill incrementally; do not attempt a repo-wide sweep, since retrofitting guards into already-typed code produces churn with no benefit.
Compatibility. Verify the PHP version matrix against the platform image and confirm the PHPStan constraint resolves against the version already in composer.lock. Because PHPStan often runs as a separate CI binary rather than a Composer dependency, confirm the stubs load correctly under that arrangement; a version skew between the CI PHPStan binary and the package's stubs is the most likely silent failure. Larastan users should validate that Laravel's own type extensions do not conflict with or shadow the package's narrowing.
Sequencing.
phpstan.neon if opt-in.mixed handling is genuinely needed.Maintenance. Ongoing cost is low but non-zero: the package must be bumped in lockstep with PHPStan majors, and that bump is the only routine maintenance event. Budget a small recurring task each time the static-analysis toolchain moves. Because it is dev-scoped, it does not affect production artifacts or deploy size if installed with --no-dev.
Support. No commercial support and no SLA. Expect GitHub issues as the only channel, with response times dependent on a small maintainer group. Teams with strict supply-chain or vendor-support policies should treat this as an unsupported dependency and plan to vendor or fork it if it becomes load-bearing for CI.
Scaling. Runtime cost is negligible — the guards compile to the same primitive checks developers would write by hand — so there is no throughput or memory concern at any realistic scale. The scaling constraint is organizational, not technical: the benefit scales with the number of engineers who understand the static-analysis payoff, and the cost scales with the number of PHPStan upgrades the team performs per year.
Failure modes.
string guard does not reject empty or malformed strings. This is the most probable source of production bugs introduced alongside adoption.mixed handling.webmozart/assert or spatie/laravel-data setup, forcing a Composer resolution compromise.Ramp-up. Minimal for individual developers — the API mirrors is_* and instanceof idioms, so there is essentially no new mental model. The real ramp-up cost is educating the team on when to reach for a guard versus a validator versus a DTO, and on the discipline of running PHPStan locally rather than only in CI. Allow roughly a sprint to move from pilot to comfortable default usage in the target module.
How can I help you explore Laravel packages today?