OO in D8: Being Static vs. Being Called Static (Part 2)
Object-Oriented Design in Drupal 8 Mini-Series
By Tobias Stöckler
It's been a while since I visited the Symfony Summit in Cologne in the beginning of July. I had two days of training there, one of which was on the topic of Object-Oriented Design. All other participants used Symfony on a daily basis, but none of them had worked with Drupal before, at least not in-depth. So, as a Drupal 8 core developer, I had a unique perspective on the presented topics. There were three things in particular that stood out to me in the training, and I'd like to share them with you as part of this mini-series. The first post was about Interfaces vs. Abstract Classes.
*/
In the Drupal community, Crell can perhaps be considered the father of object-orientation. One of the things he repeatedly brought up in the issue queue is that static methods should be discouraged. Static methods can have no object state and thus can be called without an actual object instance. In Drupal 8 many of Drupal's functions have been moved to static methods in utility classes. For example check_plain()
is now String::checkPlain()
. Following Crell's advice, we should make this function no longer static so that we can inject the String
class into classes that need it. Such a class can then just do $this->stringUtility->checkPlain()
. (It should be noted that for utility functions specifically Crell has not actually proposed this pattern (as far as I'm aware of), but bear with me.) This has the advantage that the String
class is now swappable all of a sudden; the class name is no longer hardcoded. In procedural code, however, (and, yes, Drupal 8 will still contain lots of procedural code!) we need to do
<span style="color: #000000"><span style="color: #0000BB"><?php<br>$string_utility </span><span style="color: #007700">= new </span><span style="color: #0000BB">String</span><span style="color: #007700">();<br></span><span style="color: #0000BB">$string_utility</span><span style="color: #007700">-></span><span style="color: #0000BB">checkPlain</span><span style="color: #007700">();<br></span><span style="color: #0000BB">?></span></span>
(Note that in PHP 5.4 this could be written in one line.) This is much more tedious that simply writing String::checkPlain()
and we need to create an object for no benefit. Above the benefit of that was swappability but here the class name is still harcoded.
In the training I learned a way to have the best of both worlds. In PHP you can actually call static methods in a non-static way. In the given example, you can write $string_utility->checkPlain()
even though checkPlain()
is a static method. Initially I thought this was one of those weird, magical PHP WTFs, but for the problem at hand it is in fact quite useful because it means we can leave checkPlain()
as a static method but in our classes act as though it weren't. That is, we can properly inject a string utility into our classes and call $this->stringUtility->checkPlain()
while procedural code can still simply call String::checkPlain()
.
I would like to propose that we actually start following this pattern for Drupal 8. The hard-coded references to classes such as String
or others are increasing and this would be a nice way to circumvent that. Even if we do not want to put all the utility classes in the dependency injection container, we could still set up the utility objects in the constructor of a class and then use them in the depicted way. That would improve the "unitness" of our unit tests, by not relying on all the utility classes, and also open the door for future refactoring.