Building Clear Rules for Your Data

Check out this cool demo app: PHP Array Box on GitHub.

Here's a simple tip to remember: When your array descriptions in PHPDoc start needing multiple lines, extra notes, or layered types, you've basically sketched out a class. It's time to own up and make it official.

Kicking Off: That Sneaky $data Habit We All Ignore

You know it's lurking in pretty much every PHP project out there.

function handle(array $data): void
{
    // 🤞 good luck
}

It begins so innocently – maybe a rushed mockup or a tight schedule, with promises to clean it up soon.

Fast forward a bit, and suddenly $data turns into a chaotic mess:

  • keys without any explanations
  • hidden switches that carry secret implications
  • checks for validity scattered and repeated everywhere
  • plus a PHPStan type hint that reads like a dense agreement

When you're using arrays to represent key ideas in your app's world, it's not giving you options – it's piling on hidden complications that slow everything down.

Looking Back: How Arrays Became Our Go-To in PHP

Hey, let's cut ourselves some slack – PHP kind of encouraged this approach from the start.

In the old days, we dealt with:

  • no way to define fixed value sets
  • loose rules on data types
  • properties you could change anytime
  • basic tools for spotting issues before runtime

And many tools and libraries just said, "Hey, toss in an array, it'll work."

Arrays felt like:

  • a breeze to set up
  • quick for slapping together code
  • but a nightmare to understand or maintain over time

Those days are long gone, especially since PHP 8 came along.

Now, we've got awesome features like:

  • immutable data holders
  • built-in value lists
  • shortcut ways to build classes
  • strict checks on types
  • advanced analyzers that really lock in your designs

Sticking with arrays for core app logic in the coming years? That's not being efficient; it's just skipping the better path.

Main Point: Arrays Don't Lock In Your Promises

Think of an array as just a basic holder. But a real data agreement is like a solid commitment.

With arrays, you get:

  • room for all sorts of wrong setups
  • hidden logic buried in the structure
  • reliance on notes and self-control to keep things straight

On the flip side, proper classes:

  • guard against bad states automatically
  • make your goals crystal clear
  • spot problems right away and make noise about them

If a piece of your code needs particular info to run, give that info its own identity, a clear form, and some built-in guidelines.

Warning Sign: When Array Definitions Spiral Out of Control 🚨

This is often where the trouble really ramps up:

/**
 * @param array{
 *   id: int,
 *   email: non-empty-string,
 *   status: 'active'|'inactive',
 *   profile?: array{
 *     firstName: string,
 *     lastName: string,
 *     age?: int<0, 120>
 *   },
 *   meta?: array<string, scalar>
 * } $user
 */
function processUser(array $user): void
{
}

Let's face it head-on:

  • It's not adaptable at all
  • Hard to scan or follow
  • Zero chance of reusing it easily

Essentially, you've got a class pretending to be a plain array.

Solid Advice (Jot This Down Somewhere Visible)