laravel/helpers
Backwards compatibility layer restoring Laravel 5.8's global helper functions—array, string, and URL helpers—in newer Laravel releases. Install with Composer; new helpers are not accepted. Modern equivalents are available as static methods on the Arr and Str classes for older codebases.
Architecture fit. laravel/helpers is a deliberately thin compatibility shim, not an architectural dependency. It ships a single files-autoloaded helpers.php of if (! function_exists(...)) blocks that each forward to Illuminate\Support\Arr or Illuminate\Support\Str. There is no service provider, no config, no container bindings, and no runtime hooks — it just makes global functions exist. For a TPM this is the ideal shape for a bridging package: it changes nothing about how the application is structured, adds no boot cost beyond parsing one small file, and can be removed by a single composer remove once the last reference is gone. It fits any Laravel app on 5.8-era code migrating forward, and it fits the framework itself (the vendor owns it), so version support is maintained in lockstep with major releases rather than left to a third party.
Integration feasibility. Extremely high and almost entirely gated on Composer semantics rather than engineering effort. The install is composer require laravel/helpers:^1.8 on the upgrade branch. The only real feasibility question is version constraint overlap: v1.8.3 adds illuminate/support ^13.0, v1.7.2 covers Laravel 12, and earlier tags cap lower — if the constraint does not intersect the target laravel/framework version, the fix is to bump the package tag, not to force the dependency. Feasibility should be confirmed with two cheap checks (composer show laravel/helpers, grep the illuminate range) plus a function_exists() smoke test in Tinker, because "installed" does not guarantee "defined" given the guards.
Technical risk. Low in the near term, non-trivial in the drift. The risks a TPM should register:
Arr::/Str::. Treat the surface as permanently as-is.str_slug are the classic examples. This is a correctness risk that only bites at the exit stage, not at adoption.array_first, array_last, and str_contains; v1.8.1 avoided array_find_key; v1.7.1 fixed implicitly nullable params for PHP 8.4; v1.8.2 added PHP 8.5 compatibility. So the package tracks PHP majors — but each major PHP or Laravel release is a fresh patch you must land, and older tags may not be compatible with the target PHP.require-dev while production code still calls a helper. This is the highest-likelihood operational failure and it is trivially avoidable.Key questions a TPM should ask:
vendor/? That number determines whether the exit is a mechanical sweep or a funded refactor sprint.Arr::/Str:: is one-to-one for most, but the exceptions need golden tests.Stack fit. This is a Laravel-only, Composer-only package, and it is framework-official. It fits every point in the upgrade path from 5.8 forward. There is nothing to configure, nothing to publish, nothing to register. From a delivery standpoint, the meaningful "stack fit" question is not "does it work" but "where in the release sequence does it belong."
Migration path — the two-PR pattern. This is the recommended and, in my view, mandatory sequencing:
laravel/framework, add laravel/helpers, fix only genuine framework breaking changes. The test suite green is the evidence the upgrade is safe. The helper refactor does not appear in this diff.Arr:: / Str:: / Str::of(), then drop the package in the final commit.Never bundle these. The entire point of the package is that the upgrade and the cleanup are separately schedulable, separately reviewable, and separately roll-backable. Bundling them re-couples two risks that the package exists to decouple.
Compatibility and unmodifiable code. The strongest justification for this dependency is code you cannot patch: dormant Composer packages, acquired codebases, vendor plugins calling array_get or str_slug that you will not be able to change. For those, isolate reality: keep the package installed, and document in composer.json or docs/tech-debt.md why it exists and which package forces it, so the next engineer does not rip it out and break the vendor. This is the difference between a one-way door and a landmine.
Sequencing and enforcement. Three things should be sequenced alongside the two PRs:
rg call-count across the repo turns "modernization" from a scary word into a number. Do not fund a cleanup sprint before you have that number.rectorphp/rector with the Arr::/Str:: rules is the cheapest way to zero out a large mechanical count, given the approximate one-to-one mapping. Keep the package installed while converting so half-converted files still run; delete it in the final commit once rg finds nothing.During conversion, mixed style is fine — Arr::get() and array_get() can coexist in one file. Convert per-file and run touched tests, not per-helper-across-repo, because the latter produces an unreviewable diff and a nasty bisect. Before deleting each helper use, pin the tricky behaviour in a golden test (dot-notation defaults, non-ASCII str_slug input) — that test is what lets you delete the package with confidence.
Maintenance. Ongoing cost is negligible at runtime but has a predictable calendar shape: every major Laravel release (12 → 13 → …) and every PHP major (8.4, 8.5, …) requires a tag bump of this package in lockstep. That is a version-bump PR per cycle, not a feature backlog. Because the API is frozen and the vendor maintains support, the maintenance model is "keep the tag current" — the risk is a team that assumes this is a set-and-forget dependency and misses the constraint when they next bump the framework.
Support. The package is vendor-owned and MIT-licensed, with an active changelog through v1.8.3, tests in CI, and a security policy. Support for behavioural divergence from modern methods, and for new helpers, is explicitly out of scope. A TPM should set that expectation up front: internal tickets asking "can we add a helper" should be redirected to "migrate the call site," not to the package maintainers.
Scaling. Operationally zero-impact. No memory footprint of note, no connection pools, no queues, no caching layer. It parses one short PHP file at boot. It scales exactly as the framework scales, which is to say it is not a scaling concern at any point.
Failure modes. Ranked by likelihood and impact:
Call to undefined function in production only — the classic cause is the package being in require-dev while production code still calls a helper. Mitigation: put it in require, not require-dev, for any deployment where a production path calls a helper.php artisan queue:restart and restart Horizon after installing.--ignore-platform-reqs your way through it.Arr::get returns different results on edge inputs, discovered when the package is deleted. Mitigation: golden tests before deletion, not after._ide_helper.php during the transition and delete it together with the package.Ramp-up. Effectively zero for engineers — these are familiar Laravel 5.8 helpers, and the package is installed by a single Composer command with no onboarding. The real ramp-up cost is organizational, not technical: the team must internalize the bridge-not-platform framing, respect the CI freeze so the count monotonically decreases, and understand the exit is a scheduled PR rather than an emergency. That is a short conversation and a documented decision, and it is the TPM's actual deliverable here — the package itself does the rest.
How can I help you explore Laravel packages today?