Type-safe data structures and bananas without gorillas in PHP

I used to love everything about object oriented programming, ignoring everything else, when I finally got it, I thought that every piece of software should be developed using OO and if it is not, it is wrong.

Meanwhile, I was very happy studying JavaScript, then I got hit by this Functional Programming thing. The first common thought was: is it programming with functions? Yes and no. Found out that it is about functions, but it shouldn’t be imperative code inside functions, it is way beyond. Anyway, this isn’t about it, but studying FP and Functional Languages I discovered that OO isn’t a bullet-proof concept, it has some failures.

Design patterns, SOLID, GRASP etc, are principles in OO to solve problems that OO itself causes, not to essentially make it better.

Joining those Functional Programming ideas and some things I learned from JavaScript community, crossed my mind some code to show.

But first, a PHP problem. It lacks type-safe data structures. You can’t strictly set types to properties, one way to solve it is to define getters and setters. I’m going to use a reduced version of a getter/setter in the examples to ensure type safety.

Let’s imagine that we have a Swimmer with a name and a wetsuit:

Cool! name and wetsuit are strictly Strings. Can’t be any other thing. If they are public properties we could set Integers to them. And our $swimmer can swim().

Ok, let’s dive into an OO problem. Imagine that now we have a Cyclist, but who can also swim(), like we see in triathlon competitions.

Love old memes


What now?

Well, imagine that now we want a simple Cyclist, who doesn’t swim(). How to accomplish it? Extract swim() to a Trait? SwimmerInterface? Cyclist and SwimmerCyclist? What if we need a Runner for a complete Triathlete? SwimmerCyclistRunner? A Triathlete who implements Interfaces and use Traits? Then classes will be only type declarations and implementations will be divided into Traits? How to test all this? OMG!

The problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle. — Joe Armstrong

If you have referentially transparent code, if you have pure functions all the data comes in its input arguments and everything goes out and leave no state behind it’s incredibly reusable. — Joe Armstrong

Pure functions

What if we split behavior from data into pure functions? swim(), ride() and run() as pure functions expecting exactly what they need to be called successfully?

First, let’s define our type-safe data structures using interfaces:

And the implementations that we’ll be suffixing with Type:

Note that this is only to accomplish type-safe data structures. All this boilerplate could be avoided by RFCs like Typed Properties and Property Type Hint.

But let’s keeping going and add our pure functions for each behavior:

And at least, the proof of concept, the Triathlete:

Now we can have all kinds of behavior reusability, everyone can swim() if it’s a Swimmer, everyone can ride() if it’s a Cyclist and everyone can run() if it’s a Runner. And Triathlete is all three and it can use the exact same behavior of them.

What you think? Have you already some thoughts on this approach? There are some drawbacks of splitting data and behavior? Leave some comments below.

P.S.: I know, it is a lot of boilerplate code to ensure type safety.