When Protected Isn’t Quite So

Colin DeCarlo
Vehikl News
Published in
3 min readJan 27, 2016

I’ve been developing with PHP for just about a decade now. I’d like to think that over time, I’ve seen most of what PHP has to offer. I’ve come to appreciate some of the things that make PHP an honest to goodness great language: exceptionally low barrier to entry, wide availability and an extensive core library — just to name a few. As I continue to develop with PHP, I continue to learn features that I didn’t know existed.

A few months back, I came across a feature of the language that I was unfamiliar with and, to be honest, was taken aback by initially. I learned that instances of the same class have access to each other’s protected attributes and methods.

Here’s an example

Although this behaviour is well documented (and isn’t unique to PHP), I wasn’t a fan of it. I felt as though it violated the principles of encapsulation and it was this feeling that initially stopped me from exploring the possible benefits it could provide to developers.

A new horizon

Recently though, I turned a corner. My feelings towards protected and private attributes being available to instances of the same class have changed. Being able to applying this knowledge has allowed me to do some pretty interesting things and overall, has made my code better.

As a concrete example, earlier this week I was writing some code for a class which contained a protected collection of data. This class was responsible for obtaining the data on its own and exposed an api which allowed consumers to filter the data and ask for aggregated information.

A trivial example of what Im describing, “A class which encapsulates a dataset and provides and api for filtering and aggregating

When it came to filtering the data, I had to make an important decision. My first option was to allow instances of this class to be mutated through the use of its filters. Option 2, I could make instances immutable and have the filters return a new instance of the class containing the filtered data.

At first, I allowed the instances to be mutated, it was simpler, supported what I needed at the time and used less code.

The “odd” filter mutates the instance and returns itself

Down the yellow brick road

Not long down the road did I discover use cases where allowing the instance to mutate could cause pretty strange and hard to debug problems. One such case is simply using the mutable instance as a parameter to another function. When the function returns, you can hope that the instance hasn’t been changed, but there are no guarantees. Unfortunately, you’re now at the mercy of the function which isn’t a great place to be under any circumstance.

Ultimately, making the instances immutable was the correct course of action. However, the requirements that the instances be immutable and obtain their own data seemed to be at odds with one another.

I considered adding a new “undocumented” parameter to the constructor to act as the initial dataset.

The “odd” filter creates and returns a new instance of itself with a filtered dataset

I felt though that allowing something like this broke the encapsulation I was striving for. After all, if you’re able to dictate what the data is, there is no real guarantee of compatibility between it (the data) and the api provided by the class.

The solution

It was then that I remembered that instances of the same class have access to each others protected (and private) attributes and methods. I could simply instantiate a new instance of the class inside the existing instance and set the data of the new instance to the filtered data of the existing instance.

The “odd” method now instantiates and returns a new instance of the Numberset class. Before being returned, the instance’s protected $numbers property is set to the filtered data.

Doing this allowed me to maintain the integrity of my encapsulation since the protected data was only allowed to be manipulated by an object which has an intimate understanding of it.

In the end, I feel really good about the shape of the code and the behaviour that instances of this class expose. Having access to the protected attribute meant that I didn’t have to make any compromises with my design either. All in all, I’ll call this a win.

--

--