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

Helpers Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

laravel/helpers is a zero-config Composer shim. It re-declares the global helpers that shipped with Laravel 5.8 — array_get, array_set, array_add, array_pluck, array_first, array_wrap, str_limit, str_slug, str_random, studly_case, camel_case, snake_case, starts_with, ends_with, and friends — and each one forwards straight to the modern Illuminate\Support\Arr / Illuminate\Support\Str method. There is no service provider, no config file, no publishable assets. It arrives via Composer's files autoloader.

Minimal steps:

  1. Install it on the branch where you are doing the framework upgrade — not on main:

    composer require laravel/helpers
    
  2. Confirm the version you got actually supports your framework:

    composer show laravel/helpers
    composer show laravel/helpers | grep illuminate
    

    The tags track Laravel releases: v1.8.3 adds illuminate/support ^13.0, v1.7.2 covers Laravel 12, v1.7.0 covers 11, v1.6.0 covers 10, v1.5.0 covers 9. If the constraint doesn't overlap your laravel/framework, bump the package tag — do not force the install.

  3. Verify the functions are live, because "installed" is not the same as "defined" (every block is wrapped in if (! function_exists(...)), and PHP 8 natives shadow some of them):

    php artisan tinker
    >>> var_dump(
    ...     function_exists('array_get'),     // true
    ...     function_exists('str_slug'),      // true
    ...     function_exists('str_contains')   // true — but it's PHP's native one, see Gotchas
    ... );
    
  4. First real use case: run your existing test suite against the upgraded framework without touching application code. That is the entire value proposition — the framework bump stays a small dependency diff, and the helper modernization becomes a separate, schedulable PR.

Where to look first: vendor/laravel/helpers/src/helpers.php. It's a short file of if (! function_exists('x')) { function x(...) { return Arr::... } } blocks. Reading it top to bottom gives you the exact list of helpers you got and the exact class method each maps to — that mapping is your refactor checklist. Then run composer why laravel/helpers to find out whether you added it deliberately or inherited it from a transitive dependency.

Implementation Patterns

Two PRs, not one. The primary pattern is upgrade-first, refactor-later:

  • PR 1: bump laravel/framework, add laravel/helpers, fix only genuine breaking changes. Green suite = upgrade shipped, revert path is trivial.
  • PR 2 (days or sprints later): mechanically replace globals with Arr:: / Str:: / Str::of(), then composer remove laravel/helpers.

Never bundle them. The package exists precisely so you don't have to.

Size the refactor before you promise a date. A call count turns "modernization" from a vague fear into a number:

rg -oN --no-filename -g '!vendor' -g '!node_modules' \
  '\b(array_get|array_set|array_add|array_pluck|array_first|array_last|array_wrap|array_dot|array_flatten|array_sort|array_has|array_only|array_except|str_limit|str_slug|str_random|str_plural|str_singular|studly_case|camel_case|snake_case|starts_with|ends_with|str_after|str_before)\(' \
  | sort | uniq -c | sort -rn

Two-hour sweep or two-week rework? That number decides whether PR 2 happens this quarter.

Freeze new usage in CI. The package is a bridge, not a policy. Snapshot the counts into ci/helper-baseline.txt and fail the build when they grow. A PHPStan/Larastan custom rule or a PHP-CS-Fixer banned-function sniff over the same list works better — it gives per-line PR annotations instead of an opaque count diff.

Automate the exit. rectorphp/rector with a Arr::/Str:: ruleset is the cheapest way to zero out a large mechanical count; most mappings are one-to-one (array_get → Arr::get, array_first → Arr::first, str_limit → Str::limit, str_random → Str::random, studly_case → Str::studly). Keep the package installed while you convert so half-migrated files still execute, and delete it in a final commit once rg finds nothing. Prefer Str::of(...)->limit(...) fluent chains where readability improves, but don't rewrite logic in the same PR — that's a review nightmare.

Convert file-by-file, not helper-by-helper. A PR that touches 30 files to remove one function name is unreviewable and bisects badly. Convert per class, run the touched tests, commit. Mixed style in one codebase during the transition is completely fine.

Isolate code you can't modify. The strongest legitimate reason to keep this dependency long-term is dormant Composer packages, acquired codebases, or vendor plugins calling array_get that you cannot patch. In that case leave the package installed and document in composer.json or docs/tech-debt.md why it's there and which package forces it, so nobody rips it out and breaks the vendor at runtime.

Pin the semantics with golden tests before deleting a call. Some helpers are not byte-identical to the method you're replacing. Before the final removal, write a test that pins the current behaviour for the risky ones:

$this->assertSame('fallback', array_get($data, 'deep.missing.key', 'fallback'));
$this->assertSame(['a', 'b'], array_wrap('a'));
$this->assertSame('foo-bar', str_slug('Foo Bar'));
$this->assertSame('café', ...); // non-ASCII transliteration is where they diverge

The test is what lets you delete the package with confidence instead of hope.

Get deployment parity right. If any production code path still calls a helper, the package belongs in require, never require-dev — otherwise you get Call to undefined function array_get() in production only. After deploying, restart long-lived workers (php artisan queue:restart) and reload PHP-FPM/OPcache, since those processes were booted from a file set that didn't include the helpers.

Give static analysis and your IDE a bridge. Larastan/PHPStan and PhpStorm don't know these globals exist, so they'll flag them as undefined and refuse autocomplete. Generate a small _ide_helper.php-style stub of function array_get(...) signatures for the transition window and delete it in the same commit that removes the package.

Reviewer checklist for new code. One line in CONTRIBUTING.md — "new code uses Arr:: / Str::; laravel/helpers is legacy-only" — plus a CI rule enforces the intent far better than tribal knowledge.

Gotchas and Tips

The API is frozen by design. The README states it outright: "We are not accepting new helpers." Do not file issues asking for a str_* addition, and do not expect a behavioural gap versus the Arr::/Str:: counterpart to be patched. Treat every helper as "as-is, forever." If you need something new, write it in your own code as a class method.

The function_exists() guards make load order matter. Every helper is only declared if nothing else already defined that name. If your app has a legacy app/helpers.php with its own array_get, or an older package ships a competing polyfill, you silently get one implementation and not the other. Diagnose it directly rather than guessing:

$r = new ReflectionFunction('array_get');
echo $r->getFileName(); // which package actually won

If two definitions exist, rename yours — don't try to out-order Composer's files autoloader.

PHP 8 natives shadow three of them. str_contains, str_starts_with, and str_ends_with are built into PHP 8+, so the package's guarded str_contains never registers. That matters because Illuminate\Support\Str::contains accepts an array of needles, while the native str_contains() accepts only a string — code that was "working" through the helper can suddenly throw a TypeError when someone passes an array:

str_contains($haystack, ['a', 'b']); // TypeError on PHP 8
Str::contains($haystack, ['a', 'b']); // correct

Grep for array-needle call sites before you upgrade, not after.

The functions delegate to modern classes, so semantics are modern, not 5.8. You get Str::slug()'s transliteration (not the 5.8 one) for str_slug, Str::plural()'s count-aware overload for str_plural, and Arr::first()'s callback signature for array_first. This is usually what you want — but it means "backwards compatibility" is about names and signatures, not about identical output in edge cases.

Pin ^1.8.0 or newer. v1.8.0 fixed genuine infinite loops in array_first, array_last, and str_contains; v1.8.1 avoided a problematic array_find_key call; v1.8.2 added PHP 8.5 compatibility. Older tags on modern runtimes can hang a request rather than error — the worst kind of bug.

Don't force the install with --ignore-platform-reqs. If composer require fights you over illuminate/support, the package tag is simply too old for your framework. Bump the tag, or stay on the previous framework. Forcing it gives you a helper file that references methods that don't exist in your Arr/Str, and you find out at runtime in production.

Fresh projects should not install this. It is a migration bridge. A brand-new Laravel 12/13 app has zero reason to add it — starting there means you've made a legacy decision before writing a line of code.

Performance is a non-issue. Every helper is one function call wrapping a static method — nanoseconds. If someone argues against the package on performance grounds, the real argument is code style, and the real fix is the Rector PR.

There are no extension points. No config, no service provider, no container binding. You cannot configure or override a helper's behaviour; the only lever is defining the function yourself first, which is exactly the load-order footgun above. If you need different behaviour, add a differently-named method in your own code and refactor call sites to it.

Upgrade in lockstep. The package's only job is tracking framework versions. Add "bump laravel/helpers alongside laravel/framework" to your upgrade runbook; a stale shim on a new framework is the most common way this dependency breaks a deploy.

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.
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo
bernskioldmedia/laravel-harvest
bernskiold/laravel-data-scrubber
bernskiold/laravel-currency-converter
bernskiold/laravel-campaign-monitor
bernskioldmedia/laravel-autotranslate
siberfx/telegram-bot
roy-sandip/laravel-view-extended
gregsphotography/site-builder-core
roy-sandip/laravel-view
anodyne/blade-fluentui-icons
webx-ui/module-catalog-collections