Moving between JavaScript and PHP is fun... until you touch arrays.
In JavaScript, chaining array methods feels natural:
arr.map().filter().reduce()
In PHP?
You can do similar things, but it often feels fragmented, noisy, or
less expressive.
That's why I built JsArray --- a small PHP library inspired by
JavaScript arrays, focused on readability, predictability, and
developer happiness.
What is JsArray?
JsArray is a lightweight wrapper around native PHP arrays that gives
you familiar methods like:
-
map -
filter -
reduce -
forEach -
find -
every -
some
All chainable. All explicit. All pure PHP.
$result = JsArray::from([1, 2, 3, 4])
->map(fn($n) => $n * 2)
->filter(fn($n) => $n > 4)
->toArray();
// [6, 8]
No magic. No macros. Just clean, readable code.
Immutable by Default (Safe Mode 🛡️)
By default, JsArray is immutable.
That means every operation returns a new instance, and the original
array stays untouched.
$original = JsArray::from([1, 2, 3]);
$doubled = $original->map(fn($n) => $n * 2);
$original->toArray(); // [1, 2, 3]
$doubled->toArray(); // [2, 4, 6]
Why this matters
- No accidental side effects
- Easier debugging
- More predictable behavior
- Very familiar if you come from JavaScript or FP-style code
Mutable Mode (When You Want Performance ⚡)
Sometimes, you do want to mutate the array directly --- especially in
performance-critical paths.
In mutable mode, methods modify the same instance instead of
creating new ones.
$array = JsArray::from([1, 2, 3])->mutable();
$array->map(fn($n) => $n * 2);
$array->filter(fn($n) => $n > 2);
$array->toArray(); // [4, 6]
Final Thoughts
If you:
- write PHP daily
- enjoy JavaScript-style APIs
- care about readable, maintainable code
Then JsArray might feel right at home.
I’m still iterating on it, so feedback, ideas, and criticism are very welcome 🙌
DX matters — we stare at this code all day anyway.
Top comments (6)
There are already wrapper libraries like github.com/illuminate/collections and github.com/doctrine/collections.
If you are running PHP 8.5 the best way to chain functions is to use the pipe operator
The benefit is that there is no need to create an object with methods that can't change.
The negative is that it is more verbose.
For the verbosity to go away we have to wait until partial function application is added and then we can write.
Illuminate and Doctrine are solid and well-established — JsArray isn’t trying to replace them.
The goal was:
agree the pipe operator (especially with partial application) is the ideal long-term direction for PHP. Until then, JsArray is just an ergonomic option for that style today.
So I see JsArray as a DX experiment, not “the best” or “the only” way — and definitely not a replacement for native functions or future language features.
Really appreciate the thoughtful comment 🙌
Discussions like this are exactly why I shared the project.
On the immutablity, it isn't that big of a feature, because the input for the class is going to be a variable most of the time.
So the original array is not going to change, unless people do something like
While I think it is a good effort, in the world with AI agents writing code there is less need for wrapper libraries.
Actually, JsArray does differ in terms of performance and memory usage, depending on whether you use immutable or mutable mode.
I agree it’s not a big deal — this project wasn’t meant to be groundbreaking.
It’s been a long time since I consistently worked on open-source, so I built JsArray mainly as practice and as a way to reignite my passion for bigger things.
Most of the code was written with the help of an AI agent, while I reviewed it, guided it, and corrected mistakes along the way.
Thanks for the discussion
True but that is why the pipe operator or using the array functions with temporary variables a better choice than a builder pattern object. Composition prevents side effects.
If you want the best performance a single loop is the fastest.
All DX comes with overhead, it is up to us to decide the benefits outweigh the negatives.
Yeah, absolutely—everything always comes at a cost, so a developer has to decide what fits their needs.