DEV Community

Omar Anwar
Omar Anwar

Posted on

I Missed JavaScript Arrays… So I Rebuilt Them in PHP 🐘

Moving between JavaScript and PHP is fun... until you touch arrays.

In JavaScript, chaining array methods feels natural:

arr.map().filter().reduce()
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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.

Links: https://github.com/omer73364/jsarray

Top comments (6)

Collapse
 
xwero profile image
david duymelinck • Edited

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

$result = [1,2,3]
 |> (fn($arr) => array_map(fn($n) => $n * 2, $arr))
 |> (fn($arr) => array_filter($arr, fn($n) => $n > 4));
Enter fullscreen mode Exit fullscreen mode

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.

$result = [1,2,3]
 |>array_map(fn($n) => $n * 2, ?)
 |>array_filter(?, fn($n) => $n > 4);
Enter fullscreen mode Exit fullscreen mode
Collapse
 
omar_anwar profile image
Omar Anwar

Illuminate and Doctrine are solid and well-established — JsArray isn’t trying to replace them.

The goal was:

  • a JS-like mental model for people jumping between JS and PHP
  • explicit immutability by default, with an opt-in mutable mode
  • readable chains without nesting or temporary variables
  • zero framework dependency

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.

Collapse
 
xwero profile image
david duymelinck • Edited

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.

$arr = [1, 2, 3, 4];
$result = JsArray::from($arr)
    ->map(fn($n) => $n * 2)
    ->filter(fn($n) => $n > 4)
    ->toArray();
Enter fullscreen mode Exit fullscreen mode

So the original array is not going to change, unless people do something like

$arr = [1, 2, 3, 4];
$arr = JsArray::from($arr)
    ->map(fn($n) => $n * 2)
    ->filter(fn($n) => $n > 4)
    ->toArray();
Enter fullscreen mode Exit fullscreen mode

While I think it is a good effort, in the world with AI agents writing code there is less need for wrapper libraries.

Thread Thread
 
omar_anwar profile image
Omar Anwar

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

Thread Thread
 
xwero profile image
david duymelinck

JsArray does differ in terms of performance and memory usage, depending on whether you use immutable or mutable mode.

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.

$new= [];
foreach([1,2,3,4] as $value){
   if($value < 4) {
      continue
   }

   $new[] = $value*2;
}
Enter fullscreen mode Exit fullscreen mode

All DX comes with overhead, it is up to us to decide the benefits outweigh the negatives.

Thread Thread
 
omar_anwar profile image
Omar Anwar

Yeah, absolutely—everything always comes at a cost, so a developer has to decide what fits their needs.