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)