azjezz/psl
PSL is a PHP standard library inspired by hhvm/hsl, offering consistent, well-typed, async-ready APIs for collections, networking, I/O, cryptography, terminal UI, and type-safe validation—replacing fragile PHP primitives with predictable alternatives. Requires PHP 8.4+.
Vec, Dict, Str, and Async components directly address Laravel’s reliance on raw arrays, str_* functions, and callback-based async patterns (e.g., queues, jobs). This reduces boilerplate and improves maintainability.Async/Fiber integration could replace Laravel’s Illuminate\Bus or Laravel\Horizon for lightweight, structured concurrency (e.g., batch processing, real-time APIs). Unchanged in 6.3.0 — no async work landed, so this remains aspirational rather than de-risked.Vector/Map/Set could augment or replace Laravel Collections (Illuminate\Support\Collection) for stricter typing and functional operations.Type\numeric(), which fills a real gap for Laravel request validation — numeric strings from query params, form posts, and CSV imports keep their original type instead of being silently cast, and Stringable objects (e.g. Laravel’s Stringable, backed enums with string values, money/quantity value objects) coerce cleanly. This is the single most Laravel-relevant addition in the release.TCP/TLS/HTTP components could underpin Laravel’s HTTP client (Guzzle) or replace Symfony\Component\HttpClient for low-level control. 6.3.0 hardens HTTP\Client response parsing (see risk table), which strengthens the security case for egress paths but introduces a new exception surface.Async or Type validation).Async\run) would require careful sequencing.Psalm/PHPStan plugins enable gradual adoption by surfacing type errors early, but Laravel’s built-in tools (e.g., php artisan make:model) may need updates. Note 6.3.0’s Dict\diff() PHPDoc correction (scalar|null|resource|Stringable) is type-only and runtime-neutral, but expect a small burst of new static-analysis findings on first upgrade if Dict\diff() is in use.^6.2 to ^6.3 is low-effort. One behavioral change (HTTP ProtocolException) needs a compatibility check before bumping production HTTP egress.| Risk Area | Severity | Mitigation Strategy |
|---|---|---|
| Breaking changes | High | Start with non-critical paths (e.g., DTO validation). 6.3.0 itself is additive; the real risk remains cross-minor API churn in Type/Async. |
| Async complexity | High | Isolate PSL Async to specific services (e.g., workers). Untouched by 6.3.0 — no new evidence to lower this. |
| HTTP client behavior change (6.3.0) | Medium | HTTP\Client now raises ProtocolException on invalid/unsupported Transfer-Encoding (including repeated fields) instead of falling back to Content-Length; conflicting Content-Length values are rejected in HTTP/1.1 and H2 (identical duplicates still accepted). Audit any PSL-based egress to third-party or internal proxies, add ProtocolException handling, and prefer chunked precedence explicitly. Security-positive (anti-smuggling/desync), but a new failure mode. |
| Type system friction | Medium | Use PSL’s Type for input validation only. Type\numeric() reduces custom regex/is_numeric glue, but it preserves input type — downstream code must not assume int/float. Standardize on explicit casts at boundaries. |
| Performance overhead | Low | Benchmark PSL vs. native PHP (e.g., Vec vs. array_map). Type\numeric() adds a coercion hop; negligible, but measure on hot request paths. |
| Vendor lock-in | Low | PSL’s MIT license and modularity reduce risk. 6.3.0 shows healthy external contribution (3 first-time contributors). |
Async, Type, Vec) offer the highest ROI? 6.3.0 makes Type a clearer first win via Type\numeric().Async\run wrapping job execution)?Illuminate\Bus or coexist? No 6.3.0 movement here — treat as unresolved.non_empty_string vs. string)?Type\numeric() first — query-string pagination and filters, money/quantity fields, or CSV/import pipelines — and what is our policy on type-preserving validation vs. eager casting?TCP/HTTP components outperform Guzzle/Symfony HTTP clients enough to justify the stricter-parsing operational burden introduced in 6.3.0?Psalm/PHPStan plugins with Laravel’s built-in tools?mago or phpstan-extension replace Laravel’s IDE helpers?Async/HTTP/Type for request validation and concurrent processing. Type\numeric() (6.3.0) is directly usable for pagination, sort indices, price/quantity params, and webhook numeric fields.Type for input validation (e.g., API payloads, form data).Vec/Dict for functional transformations (e.g., ETL, reporting).HTTP\Client for outbound calls where strict response framing (6.3.0) is a security requirement.Closure-based Laravel events.Phase 1: Validation and DTOs (Low Risk) — expanded by 6.3.0
Type (e.g., API request DTOs).use Psl\Type;
$userType = Type\shape([
'name' => Type\non_empty_string(),
'email' => Type\email_address(),
'balance' => Type\numeric(), // new in 6.3.0 — '1.23' stays a string
]);
$validated = $userType->coerce(request()->all());
Type\numeric() accepts ints, floats, numeric strings, and Stringable objects whose string value is numeric, preserving the input type. Use it to retire ad-hoc is_numeric() checks; pair with explicit casting at the domain boundary so "numeric string stays string" is not a latent bug.Psalm plugin to catch type errors early.Phase 2: Collections (Medium Risk)
Illuminate\Support\Collection with PSL’s Vec/Dict for functional operations.use Psl\Vec;
$users = Vec\map($users, fn($user) => $user->name);
Collection macros may need PSL equivalents. If Dict\diff() is used, re-run static analysis after upgrading — 6.3.0 narrowed the PHPDoc value bound to scalar|null|resource|Stringable (runtime unchanged).Phase 3: Async/Concurrency (High Risk)
use Psl\Async;
Async\main(static function() {
$result = Async\concurrently([
fn() => processOrder(1),
fn() => sendNotification(2),
]);
});
Illuminate\Bus or Laravel\Horizon. No change in 6.3.0 — sequencing and risk posture hold.Phase 4: Networking (High Risk)
HTTP/TCP for custom protocols.use Psl\HTTP;
$response = HTTP\request('GET', 'https://api.example.com');
HTTP\Client validates every Transfer-Encoding response field (including repeated ones). Invalid or unsupported transfer codings now raise ProtocolException rather than falling back to Content-Length; valid chunked responses still win over Content-Length. Conflicting Content-Length fields are rejected in HTTP/1.1 and H2, while identical duplicates are accepted.
ProtocolException into your retry/circuit-breaker policy, and alert on it — it likely signals a broken intermediary (misconfigured proxy, CDN, or worse, a desync attempt).| Laravel Component | PSL Equivalent | Compatibility Notes |
|---|---|---|
Illuminate\Support\Collection |
Psl\Vec, Psl\Dict |
Functional APIs overlap; macros may need migration. Dict\diff() PHPDoc re-typed in 6.3.0. |
Illuminate\Bus |
Psl\Async |
Fibers vs. queues; may need adapter layer. Unchanged in 6.3.0. |
Guzzle/Symfony HTTP |
Psl\HTTP |
PSL is lower-level; middleware support needed. 6.3.0 strict framing → handle ProtocolException. |
Laravel Validator |
Psl\Type (incl. numeric()) |
Complements rather than replaces; keep Laravel rules for user-facing messages, use PSL for DTO coercion. |
| Eloquent Models | PSL Type (DTOs) |
Immutability conflicts; use PSL for validation only. |
| Blade Templates | PSL Str |
Limited impact; use for string manipulation. |
Type), now including Type\numeric() for numeric query/form/import fields.Vec/Dict).Psalm/PHPStan plugins early to catch issues.mago for enhanced type inference during migration; re-baseline after the 6.3.0 Dict\diff() PHPDoc change.ProtocolException handling landing beforehand.Vec/Dict) eliminate manual array operations; Type\numeric() retires hand-rolled numeric guards.numeric().Psalm/PHPStan for full benefits; may slow down CI, and PHPDoc-only changes (6.3.0 Dict\diff()) can shift analysis output without runtime change.Type\shape()/Type\numeric() express intent better than scattered validation rules, reducing support handoffs between API and domain teams.ProtocolException is unfamiliar territory: support staff will need a documented triage path, since this is a protocol-level failure, not a typical timeout or 5xx.Vec/Dict avoid surprise mutation and make capacity planning on data pipelines more predictable.Async, so the queue-vs-fiber capacity model is still an open, unbudgeted question.ProtocolException bursts rather than silent Content-Length fallbacks — good for correctness, but it needs retry/backoff and alerting thresholds sized before rollout.ProtocolException from HTTP\Client (6.3.0) — invalid/unsupported Transfer-Encoding, repeated transfer-coding fields, or conflicting Content-Length (HTTP/1.1 and H2; identical duplicates accepted). Presents as hard failures on previously "working" calls. Detect via exception type, alert on rate, and distinguish upstream breakage from active tampering.Type\numeric() — assertions succeed but the value keeps its original type ('1.23' stays a string). Downstream arithmetic or strict comparisons can fail or behave subtly differently. Mitigate with explicit casts at domain boundaries and static analysis.Dict\diff()'s narrowed value bound can surface new errors on upgrade despite identical runtime behavior. Pre-empt with a CI baseline diff.Type) remains the right first step and is now more attractive thanks to Type\numeric(); a single DTO or form request is enough to demonstrate value.Type\shape() + numeric(), a PSL HTTP adapter with ProtocolException handling, and a short functional-PHP primer for engineers raised on Eloquent/Collections.Type\numeric() in Phase 1 immediately, audit PSL HTTP egress before the version bump, and re-run static analysis to absorb the Dict\diff() PHPDoc change. No changes to the async risk posture or sequencing.How can I help you explore Laravel packages today?